home *** CD-ROM | disk | FTP | other *** search
/ Super Shareware Collection / Super Shareware Collection.iso / os_2 / clisp.zip / CLOS.LSP < prev    next >
Lisp/Scheme  |  1994-02-05  |  157KB  |  3,531 lines

  1. ;;;; Common Lisp Object System für CLISP
  2. ;;;; Bruno Haible 21.8.1993
  3.  
  4. ; Zur Benutzung reicht ein einfaches (USE-PACKAGE "CLOS").
  5.  
  6.  
  7. (in-package "LISP")
  8. (export '(clos))
  9. (pushnew 'clos *features*)
  10.  
  11.  
  12. (in-package "SYSTEM") ; Trotz DEFPACKAGE nötig!
  13.  
  14. (defpackage "CLOS"
  15.  
  16. (:import-from "SYSTEM"
  17.   ;; Import:
  18.   sys::function-name-p                               ; in control.d definiert
  19.   sys::block-name                                    ; in init.lsp definiert
  20. ; clos::generic-function-p                           ; in predtype.d definiert
  21. ; clos::class-p clos:class-of                        ; in predtype.d definiert
  22. ; clos::std-instance-p clos::allocate-std-instance   ; in record.d definiert
  23. ; clos:slot-value clos::set-slot-value               ; in record.d definiert
  24. ; clos:slot-boundp clos:slot-makunbound              ; in record.d definiert
  25. ; clos:slot-exists-p                                 ; in record.d definiert
  26.   compiler::memq compiler::*keyword-package*         ; in compiler.lsp definiert
  27.   compiler::%generic-function-lambda                 ; in compiler.lsp definiert
  28.   compiler::%optimize-function-lambda                ; in compiler.lsp definiert
  29. ; clos:generic-flet clos:generic-labels              ; in compiler.lsp behandelt
  30.   ;; Export:
  31. ; clos::class    ; als Property in predtype.d und type.lsp, compiler.lsp benutzt
  32. ; clos:standard-generic-function ; in predtype.d, type.lsp, compiler.lsp benutzt
  33. ; clos:slot-missing clos:slot-unbound  ; von record.d aufgerufen
  34. ; clos::*make-instance-table*          ; von record.d benutzt
  35. ; clos::*reinitialize-instance-table*  ; von record.d benutzt
  36. ; clos::initial-reinitialize-instance  ; von record.d aufgerufen
  37. ; clos::initial-initialize-instance    ; von record.d aufgerufen
  38. ; clos::initial-make-instance          ; von record.d aufgerufen
  39. ; clos:print-object                    ; von io.d aufgerufen
  40. ; clos:describe-object                 ; von user2.lsp aufgerufen
  41. ; clos::define-structure-class         ; von defstruc.lsp aufgerufen
  42. ; clos::built-in-class-p               ; von type.lsp aufgerufen
  43. ; clos::subclassp                      ; von type.lsp aufgerufen, in compiler.lsp benutzt
  44. ; clos:class-name                      ; in type.lsp, compiler.lsp benutzt
  45. ; clos:find-class                      ; in compiler.lsp benutzt
  46. ; clos::defgeneric-lambdalist-callinfo ; von compiler.lsp aufgerufen
  47. ; clos::make-generic-function-form     ; von compiler.lsp aufgerufen
  48. )
  49.  
  50. ) ; defpackage
  51.  
  52. ;;; Exportierungen: ** auch in init.lsp ** !
  53. (export '(
  54.   ;; Namen von Funktionen und Macros:
  55.   slot-value slot-boundp slot-makunbound slot-exists-p with-slots with-accessors
  56.   find-class class-of defclass defmethod call-next-method next-method-p
  57.   defgeneric generic-function generic-flet generic-labels
  58.   class-name
  59.   no-applicable-method no-primary-method no-next-method
  60.   find-method add-method remove-method
  61.   compute-applicable-methods method-qualifiers function-keywords
  62.   slot-missing slot-unbound
  63.   print-object describe-object
  64.   make-instance initialize-instance reinitialize-instance shared-initialize
  65.   ;; Namen von Klassen:
  66.   standard-class structure-class built-in-class
  67.   standard-object standard-generic-function standard-method
  68.   ;; andere Symbole:
  69.   standard ; Methoden-Kombination
  70. ))
  71.  
  72.  
  73. ;;; Vorbemerkungen:
  74.  
  75. ;; Abkürzungen:
  76. ;; std = standard
  77. ;; gf = generic function
  78. ;; <...> = (class ...), meist = (find-class '...)
  79. ;; em = effective method
  80.  
  81.  
  82. ;;; Vordefinierte Klassen:
  83. ; Metaklassen:
  84. (defvar <standard-class>)              ; hier <structure-class>
  85. (defvar <structure-class>)             ; hier <structure-class>
  86. (defvar <built-in-class>)              ; hier <structure-class>
  87. ; Klassen:
  88. (defvar <standard-object>)             ; <standard-class>
  89. (defvar <standard-generic-function>)   ; <built-in-class>
  90. (defvar <standard-method>)             ; hier <structure-class>
  91. (defvar <array>)                       ; <built-in-class>
  92. (defvar <bit-vector>)                  ; <built-in-class>
  93. (defvar <character>)                   ; <built-in-class>
  94. (defvar <complex>)                     ; <built-in-class>
  95. (defvar <cons>)                        ; <built-in-class>
  96. (defvar <float>)                       ; <built-in-class>
  97. (defvar <function>)                    ; <built-in-class>
  98. (defvar <hash-table>)                  ; <built-in-class>
  99. (defvar <integer>)                     ; <built-in-class>
  100. (defvar <list>)                        ; <built-in-class>
  101. (defvar <null>)                        ; <built-in-class>
  102. (defvar <number>)                      ; <built-in-class>
  103. (defvar <package>)                     ; <built-in-class>
  104. (defvar <pathname>)                    ; <built-in-class>
  105. (defvar <random-state>)                ; <built-in-class>
  106. (defvar <ratio>)                       ; <built-in-class>
  107. (defvar <rational>)                    ; <built-in-class>
  108. (defvar <readtable>)                   ; <built-in-class>
  109. (defvar <real>)                        ; <built-in-class>
  110. (defvar <sequence>)                    ; <built-in-class>
  111. (defvar <stream>)                      ; <built-in-class>
  112. (defvar <string>)                      ; <built-in-class>
  113. (defvar <symbol>)                      ; <built-in-class>
  114. (defvar <t>)                           ; <built-in-class>
  115. (defvar <vector>)                      ; <built-in-class>
  116.  
  117.  
  118. ;;; Low-Level-Repräsentation:
  119.  
  120. ;; Im Runtime-System gibt es den Typ "CLOS-Instanz".
  121. ;; Erste Komponente ist die Klasse.
  122.  
  123. ;; Klassen sind Structures vom Typ CLASS,
  124. ;;   erste Komponente ist die Metaklasse, zweite Komponente der Name.
  125.  
  126. ;; Der "Wert" eines Slots, der unbound ist, ist #<UNBOUND> - was sonst?
  127.  
  128. ;; siehe RECORD.D :
  129. ; (STD-INSTANCE-P obj) testet, ob ein Objekt eine CLOS-Instanz ist.
  130. ; (ALLOCATE-STD-INSTANCE class n) liefert eine CLOS-Instanz mit Klasse class
  131. ; und n-1 zusätzlichen Slots.
  132. ;; siehe IO.D :
  133. ; CLOS-Instanzen werden via (PRINT-OBJECT object stream) ausgegeben.
  134.  
  135. ; Eine Instanz für ein Objekt der Metaklasse <standard-class> besorgen:
  136. (defmacro std-allocate-instance (class)
  137.   `(allocate-std-instance ,class (class-instance-slot-count ,class))
  138. )
  139.  
  140.  
  141. ;;; globale Verwaltung von Klassen und ihren Namen:
  142.  
  143. (defun find-class (symbol &optional (errorp t) environment)
  144.   (declare (ignore environment)) ; was sollte das Environment bedeuten?
  145.   (unless (symbolp symbol)
  146.     (error #+DEUTSCH "~S: Argument ~S ist kein Symbol."
  147.            #+ENGLISH "~S: argument ~S is not a symbol"
  148.            'find-class symbol
  149.   ) )
  150.   (let ((class (get symbol 'CLASS)))
  151.     (if (not (class-p class))
  152.       (if errorp
  153.         (error #+DEUTSCH "~S: ~S benennt keine Klasse."
  154.                #+ENGLISH "~S: ~S does not name a class"
  155.                'find-class symbol
  156.         )
  157.         nil
  158.       )
  159.       class
  160. ) ) )
  161.  
  162. (defun (setf find-class) (new-value symbol &optional errorp environment)
  163.   (declare (ignore errorp environment)) ; was sollte das Environment bedeuten?
  164.   (unless (symbolp symbol)
  165.     (error #+DEUTSCH "~S: Argument ~S ist kein Symbol."
  166.            #+ENGLISH "~S: argument ~S is not a symbol"
  167.            '(setf find-class) symbol
  168.   ) )
  169.   (unless (class-p new-value)
  170.     (error #+DEUTSCH "~S: ~S ist keine Klasse."
  171.            #+ENGLISH "~S: ~S is not a class"
  172.            '(setf find-class) new-value
  173.   ) )
  174.   (let ((h (get symbol 'CLASS)))
  175.     (when (and (built-in-class-p h) (eq (class-name h) symbol)) ; auch Structure-Klassen schützen??
  176.       (error #+DEUTSCH "~S: Built-In-Klasse ~S kann nicht umdefiniert werden."
  177.              #+ENGLISH "~S: cannot redefine built-in class ~S"
  178.              '(setf find-class) h
  179.   ) ) )
  180.   (setf (get symbol 'CLASS) new-value)
  181. )
  182.  
  183. ; (CLASS-OF object) siehe PREDTYPE.D, benutzt Property CLASS.
  184.  
  185.  
  186. ;;; Slots:
  187.  
  188. #|
  189. ;; So könnten die Zugriffsfunktionen aussehen, wenn man SLOT-VALUE-USING-CLASS
  190. ;; verwendet.
  191.  
  192. ; Zugriff auf Slots von Objekten der Metaklasse <standard-class>:
  193. (defun std-slot-value (instance slot-name)
  194.   (declare (compile))
  195.   (let* ((class (class-of instance))
  196.          (slot-location (gethash slot-name (class-slot-location-table class))))
  197.     ((lambda (value)
  198.        (if (eq value unbound)
  199.          (slot-unbound class instance slot-name)
  200.          value
  201.      ) )
  202.      (cond ((null slot-location)
  203.             (slot-missing class instance slot-name 'slot-value)
  204.            )
  205.            ((atom slot-location)
  206.             ; access local slot
  207.             (sys::%record-ref instance slot-location)
  208.            )
  209.            (t
  210.             ; access shared slot
  211.             (svref (class-shared-slots (car slot-location)) (cdr slot-location))
  212.            )
  213.     ))
  214. ) )
  215. (defun std-setf-slot-value (instance slot-name new-value)
  216.   (let* ((class (class-of instance))
  217.          (slot-location (gethash slot-name (class-slot-location-table class))))
  218.     (cond ((null slot-location)
  219.            (slot-missing class instance slot-name 'setf new-value)
  220.           )
  221.           ((atom slot-location)
  222.            ; access local slot
  223.            (sys::%record-store instance slot-location new-value)
  224.           )
  225.           (t
  226.            ; access shared slot
  227.            (setf (svref (class-shared-slots (car slot-location)) (cdr slot-location))
  228.                  new-value
  229.           ))
  230. ) ) )
  231. (defun std-slot-boundp (instance slot-name)
  232.   (declare (compile))
  233.   (let* ((class (class-of instance))
  234.          (slot-location (gethash slot-name (class-slot-location-table class))))
  235.     (cond ((null slot-location)
  236.            (slot-missing class instance slot-name 'slot-boundp)
  237.           )
  238.           ((atom slot-location)
  239.            ; access local slot
  240.            (not (eq (sys::%record-ref instance slot-location) unbound))
  241.           )
  242.           (t
  243.            ; access shared slot
  244.            (not (eq (svref (class-shared-slots (car slot-location)) (cdr slot-location)) unbound))
  245.           )
  246. ) ) )
  247. (defun std-slot-makunbound (instance slot-name)
  248.   (declare (compile))
  249.   (let* ((class (class-of instance))
  250.          (slot-location (gethash slot-name (class-slot-location-table class))))
  251.     (cond ((null slot-location)
  252.            (slot-missing class instance slot-name 'slot-makunbound)
  253.           )
  254.           ((atom slot-location)
  255.            ; access local slot
  256.            (sys::%record-store instance slot-location unbound)
  257.           )
  258.           (t
  259.            ; access shared slot
  260.            (setf (svref (class-shared-slots (car slot-location)) (cdr slot-location))
  261.                  unbound
  262.           ))
  263. ) ) )
  264. (defun std-slot-exists-p (instance slot-name)
  265.   (and (gethash slot-name (class-slot-location-table (class-of instance))) t)
  266. )
  267.  
  268. ;; Zugriff auf Slots allgemein:
  269. (defun slot-value (object slot-name)
  270.   (let ((class (class-of object)))
  271.     ; Metaklasse <standard-class> gesondert betrachten
  272.     ; aus Effizienzgründen und wegen Bootstrapping
  273.     (if (eq (class-of class) <standard-class>)
  274.       (std-slot-value object slot-name)
  275.       (slot-value-using-class class object slot-name)
  276. ) ) )
  277. (defun (setf slot-value) (new-value object slot-name)
  278.   (let ((class (class-of object)))
  279.     ; Metaklasse <standard-class> gesondert betrachten
  280.     ; aus Effizienzgründen und wegen Bootstrapping
  281.     (if (eq (class-of class) <standard-class>)
  282.       (std-setf-slot-value object slot-name new-value)
  283.       (setf-slot-value-using-class new-value class object slot-name)
  284. ) ) )
  285. (defun slot-boundp (object slot-name)
  286.   (let ((class (class-of object)))
  287.     ; Metaklasse <standard-class> gesondert betrachten
  288.     ; aus Effizienzgründen und wegen Bootstrapping
  289.     (if (eq (class-of class) <standard-class>)
  290.       (std-slot-boundp object slot-name)
  291.       (slot-boundp-using-class class object slot-name)
  292. ) ) )
  293. (defun slot-makunbound (object slot-name)
  294.   (let ((class (class-of object)))
  295.     ; Metaklasse <standard-class> gesondert betrachten
  296.     ; aus Effizienzgründen und wegen Bootstrapping
  297.     (if (eq (class-of class) <standard-class>)
  298.       (std-slot-makunbound object slot-name)
  299.       (slot-makunbound-using-class class object slot-name)
  300. ) ) )
  301. (defun slot-exists-p (object slot-name)
  302.   (let ((class (class-of object)))
  303.     ; Metaklasse <standard-class> gesondert betrachten
  304.     ; aus Effizienzgründen und wegen Bootstrapping
  305.     (if (eq (class-of class) <standard-class>)
  306.       (std-slot-exists-p object slot-name)
  307.       (slot-exists-p-using-class class object slot-name)
  308. ) ) )
  309.  
  310. (defun slot-value-using-class (class object slot-name)
  311.   (no-slot-error class object slot-name)
  312. )
  313. (defun setf-slot-value-using-class (new-value class object slot-name)
  314.   (declare (ignore new-value))
  315.   (no-slot-error class object slot-name)
  316. )
  317. (defun slot-boundp-using-class (class object slot-name)
  318.   (no-slot-error class object slot-name)
  319. )
  320. (defun slot-makunbound-using-class (class object slot-name)
  321.   (no-slot-error class object slot-name)
  322. )
  323. (defun slot-exists-p-using-class (class object slot-name)
  324.   (no-slot-error class object slot-name)
  325. )
  326.  
  327. (defun no-slot-error (class object slot-name)
  328.   (declare (ignore slot-name))
  329.   (error #+DEUTSCH "Instanz ~S der Klasse ~S hat keine Slots (falsche Metaklasse)"
  330.          #+ENGLISH "instance ~S of class ~S has no slots (wrong metaclass)"
  331.          object class
  332. ) )
  333. |#
  334.  
  335. ;; Der Effizienz halber - wir wollen den Test auf <standard-class> umgehen -
  336. ;; bekommen alle Klassen (egal ob standard- oder built-in-) eine
  337. ;; slot-location-table. Außerdem können wir hier mit unbound schlecht umgehen.
  338. ;; Daher sind
  339. ;;   slot-value, set-slot-value, slot-boundp, slot-makunbound, slot-exists-p
  340. ;; nun bereits in RECORD.D enthalten.
  341.  
  342. (defsetf slot-value set-slot-value)
  343.  
  344. ;; WITH-SLOTS
  345.  
  346. (defmacro with-slots (slot-entries instance-form &body body &environment env)
  347.   (let ((vars '())
  348.         (slots '()))
  349.     (unless (listp slot-entries)
  350.       (error #+DEUTSCH "~S: Das ist keine Liste von Slots: ~S"
  351.              #+ENGLISH "~S: not a list of slots: ~S"
  352.              'with-slots slot-entries
  353.     ) )
  354.     (dolist (slot slot-entries)
  355.       (let ((var slot))
  356.         (when (consp slot)
  357.           (unless (eql (length slot) 2)
  358.             (error #+DEUTSCH "~S: unzulässige Slot/Variablen-Bezeichnung ~S"
  359.                    #+ENGLISH "~S: invalid slot and variable specification ~S"
  360.                    'with-slots slot
  361.           ) )
  362.           (setq var (first slot) slot (second slot))
  363.           (unless (symbolp var)
  364.             (error #+DEUTSCH "~S: Variable ~S sollte ein Symbol sein."
  365.                    #+ENGLISH "~S: variable ~S should be a symbol"
  366.                    'with-slots var
  367.           ) )
  368.         )
  369.         (unless (symbolp slot)
  370.           (error #+DEUTSCH "~S: Slot-Name ~S sollte ein Symbol sein."
  371.                  #+ENGLISH "~S: slot name ~S should be a symbol"
  372.                  'with-slots slot
  373.         ) )
  374.         (push var vars)
  375.         (push slot slots)
  376.     ) )
  377.     (multiple-value-bind (body-rest declarations) (sys::parse-body body nil env)
  378.       (let ((instance-var (gensym)))
  379.         `(LET ((,instance-var ,instance-form))
  380.            (SYMBOL-MACROLET
  381.              ,(mapcar #'(lambda (var slot)
  382.                           `(,var (SLOT-VALUE ,instance-var ',slot))
  383.                         )
  384.                       (nreverse vars) (nreverse slots)
  385.               )
  386.              ,@(if declarations `((DECLARE ,@declarations)))
  387.              ,@body-rest
  388.          ) )
  389. ) ) ) )
  390.  
  391. ;; WITH-ACCESSORS
  392.  
  393. (defmacro with-accessors (slot-entries instance-form &body body &environment env)
  394.   (unless (listp slot-entries)
  395.     (error #+DEUTSCH "~S: Das ist keine Liste von Slots: ~S"
  396.            #+ENGLISH "~S: not a list of slots: ~S"
  397.            'with-accessors slot-entries
  398.   ) )
  399.   (dolist (slot-entry slot-entries)
  400.     (unless (and (consp slot-entry) (eql (length slot-entry) 2))
  401.       (error #+DEUTSCH "~S: unzulässige Slot/Accessor-Bezeichnung ~S"
  402.              #+ENGLISH "~S: invalid accessor and variable specification ~S"
  403.              'with-accessors slot-entry
  404.     ) )
  405.     (unless (symbolp (first slot-entry))
  406.       (error #+DEUTSCH "~S: Variable ~S sollte ein Symbol sein."
  407.              #+ENGLISH "~S: variable ~S should be a symbol"
  408.              'with-accessors (first slot-entry)
  409.     ) )
  410.     (unless (symbolp (second slot-entry))
  411.       (error #+DEUTSCH "~S: Accessor-Name ~S sollte ein Symbol sein."
  412.              #+ENGLISH "~S: accessor name ~S should be a symbol"
  413.              'with-accessors (second slot-entry)
  414.     ) )
  415.   )
  416.   (multiple-value-bind (body-rest declarations) (sys::parse-body body nil env)
  417.     (let ((instance-var (gensym)))
  418.       `(LET ((,instance-var ,instance-form))
  419.          (SYMBOL-MACROLET
  420.            ,(mapcar #'(lambda (slot-entry)
  421.                         `(,(first slot-entry) (,(second slot-entry) ,instance-var))
  422.                       )
  423.                     slot-entries
  424.             )
  425.            ,@(if declarations `((DECLARE ,@declarations)))
  426.            ,@body-rest
  427.        ) )
  428. ) ) )
  429.  
  430.  
  431. ;;; Klassen
  432.  
  433. ; zum Bootstrappen
  434. (eval-when (compile load eval)
  435.   (defun define-structure-class (name) (declare (ignore name)) ) ; vorläufig
  436. )
  437. ; alle Spuren eines früher geladenen CLOS ausmerzen
  438. (eval-when (load eval)
  439.   (do-all-symbols (s) (remprop s 'CLASS))
  440. )
  441.  
  442. (defconstant empty-ht (make-hash-table :test #'eq :size 0))
  443.  
  444. (defstruct (class (:predicate nil) (:print-function print-class))
  445.   metaclass ; (class-of class) = (class-metaclass class), eine Klasse
  446.   classname ; (class-name class) = (class-classname class), ein Symbol
  447.   direct-superclasses ; Liste aller direkten Oberklassen
  448.   all-superclasses ; Hash-Tabelle aller Oberklassen (inkl. der Klasse selbst)
  449.   precedence-list ; angeordnete Liste aller Oberklassen (Klasse selbst zuerst)
  450.   (slot-location-table empty-ht) ; Hashtabelle Slotname -> wo der Slot sitzt
  451. )
  452.  
  453. (defstruct (built-in-class (:inherit class) (:conc-name "CLASS-") (:print-function print-class))
  454. )
  455. (proclaim '(notinline built-in-class-p))
  456.  
  457. (defstruct (structure-class (:inherit class) (:conc-name "CLASS-") (:print-function print-class))
  458. )
  459.  
  460. (defstruct (standard-class (:inherit class) (:conc-name "CLASS-") (:print-function print-class))
  461.   direct-slots             ; Liste der neu hinzugekommenen Slots (als Plisten)
  462.   slots                    ; Liste aller Slots (als Slot-Definitionen)
  463.   instance-slot-count      ; Anzahl der Slots der direkten Instanzen + 1
  464.   shared-slots             ; Simple-Vector mit den Werten aller Shared Slots
  465.   direct-default-initargs  ; Neu hinzugekommene Default-Initargs (als Pliste)
  466.   default-initargs         ; Default-Initargs (als Aliste Initarg -> Initer)
  467.   valid-initargs           ; Liste der gültigen Initargs
  468. )
  469.  
  470. ; Zugriff auf Slots von Instanzen der Klasse <class> mittels der
  471. ; defstruct-Accessoren, daher hier keine Bootstrapping-Probleme.
  472.  
  473. ; Weiter Bootstrapping
  474. (%defclos
  475.   ; Erkennungszeichen für CLASS-P
  476.   (svref (get 'class 'sys::defstruct-description) 0)
  477.   ; Built-In-Klassen für CLASS-OF
  478.   (vector 'array 'bit-vector 'character 'complex 'cons 'float 'function
  479.           'hash-table 'integer 'null 'package 'pathname 'random-state
  480.           'ratio 'readtable 'standard-generic-function 'stream 'string
  481.           'symbol 't 'vector
  482. ) )
  483.  
  484. (defun print-class (class stream depth)
  485.   (declare (ignore depth))
  486.   (print-unreadable-object (class stream :type t)
  487.     (write (class-classname class) :stream stream)
  488. ) )
  489.  
  490.  
  491. ;;; DEFCLASS
  492.  
  493. (defmacro defclass (name superclass-specs slot-specs &rest options)
  494.   (unless (symbolp name)
  495.     (error #+DEUTSCH "~S: Klassenname muß ein Symbol sein, nicht ~S"
  496.            #+ENGLISH "~S: class name ~S should be a symbol"
  497.            'defclass name
  498.   ) )
  499.   (let* ((superclass-forms
  500.            (progn
  501.              (unless (listp superclass-specs)
  502.                (error #+DEUTSCH "~S ~S: Superklassen-Liste erwartet statt ~S"
  503.                       #+ENGLISH "~S ~S: expecting list of superclasses instead of ~S"
  504.                       'defclass name superclass-specs
  505.              ) )
  506.              (mapcar #'(lambda (superclass)
  507.                          (unless (symbolp superclass)
  508.                            (error #+DEUTSCH "~S ~S: Oberklassenname muß ein Symbol sein, nicht ~S"
  509.                                   #+ENGLISH "~S ~S: superclass name ~S should be a symbol"
  510.                                   'defclass name superclass
  511.                          ) )
  512.                          `(FIND-CLASS ',superclass)
  513.                        )
  514.                      superclass-specs
  515.          ) ) )
  516.          (accessor-def-forms '())
  517.          (slot-forms
  518.            (progn
  519.              (unless (listp slot-specs)
  520.                (error #+DEUTSCH "~S ~S: Slotspezifikationen-Liste erwartet statt ~S"
  521.                       #+ENGLISH "~S ~S: expecting list of slot specifications instead of ~S"
  522.                       'defclass name slot-specs
  523.              ) )
  524.              (mapcar #'(lambda (slot-spec)
  525.                          (let ((slot-name slot-spec) (slot-options '()))
  526.                            (when (consp slot-spec)
  527.                              (setq slot-name (car slot-spec) slot-options (cdr slot-spec))
  528.                            )
  529.                            (unless (symbolp slot-name)
  530.                              (error #+DEUTSCH "~S ~S: Slotname muß ein Symbol sein, nicht ~S"
  531.                                     #+ENGLISH "~S ~S: slot name ~S should be a symbol"
  532.                                     'defclass name slot-name
  533.                            ) )
  534.                            (let ((accessors '())
  535.                                  (readers '())
  536.                                  (writers '())
  537.                                  (allocation '())
  538.                                  (initargs '())
  539.                                  (initform nil) (initer nil)
  540.                                  (types '())
  541.                                  (documentation nil))
  542.                              (when (oddp (length slot-options))
  543.                                (error #+DEUTSCH "~S ~S: Slot-Optionen zu Slot ~S sind nicht paarig."
  544.                                       #+ENGLISH "~S ~S: slot options for slot ~S don't come in pairs"
  545.                                       'defclass name slot-name
  546.                              ) )
  547.                              (do ((optionsr slot-options (cddr optionsr)))
  548.                                  ((atom optionsr))
  549.                                (let ((optionkey (first optionsr))
  550.                                      (argument (second optionsr)))
  551.                                  (case optionkey
  552.                                    ((:READER :WRITER)
  553.                                     (unless (function-name-p argument)
  554.                                       (error #+DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist kein Funktionsname."
  555.                                              #+ENGLISH "~S ~S, slot option for slot ~S: ~S is not a function name"
  556.                                              'defclass name slot-name argument
  557.                                     ) )
  558.                                     (case optionkey
  559.                                       (:READER (push argument readers))
  560.                                       (:WRITER (push argument writers))
  561.                                    ))
  562.                                    (:ACCESSOR
  563.                                     (unless (symbolp argument)
  564.                                       (error #+DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist kein Symbol."
  565.                                              #+ENGLISH "~S ~S, slot option for slot ~S: ~S is not a symbol"
  566.                                              'defclass name slot-name argument
  567.                                     ) )
  568.                                     (push argument accessors)
  569.                                     (push argument readers)
  570.                                     (push `(SETF ,argument) writers)
  571.                                    )
  572.                                    (:ALLOCATION
  573.                                     (when allocation
  574.                                       (error #+DEUTSCH "~S ~S, Slot-Option ~S zu Slot ~S darf nur einmal angegeben werden."
  575.                                              #+ENGLISH "~S ~S, slot option ~S for slot ~S may only be given once"
  576.                                              'defclass name ':allocation slot-name
  577.                                     ) )
  578.                                     (case argument
  579.                                       ((:INSTANCE :CLASS) (setq allocation argument))
  580.                                       (t (error #+DEUTSCH "~S ~S, Slot-Option zu Slot ~S muß den Wert ~S oder ~S haben, nicht ~S"
  581.                                                 #+ENGLISH "~S ~S, slot option for slot ~S must have the value ~S or ~S, not ~S"
  582.                                                 'defclass name slot-name ':instance ':class argument
  583.                                    )) )  )
  584.                                    (:INITARG
  585.                                     (unless (symbolp argument)
  586.                                       (error #+DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist kein Symbol."
  587.                                              #+ENGLISH "~S ~S, slot option for slot ~S: ~S is not a symbol"
  588.                                              'defclass name slot-name argument
  589.                                     ) )
  590.                                     (push argument initargs)
  591.                                    )
  592.                                    (:INITFORM
  593.                                     (when initform
  594.                                       (error #+DEUTSCH "~S ~S, Slot-Option ~S zu Slot ~S darf nur einmal angegeben werden."
  595.                                              #+ENGLISH "~S ~S, slot option ~S for slot ~S may only be given once"
  596.                                              'defclass name ':initform slot-name
  597.                                     ) )
  598.                                     (setq initform `(QUOTE ,argument)
  599.                                           initer (make-initer argument)
  600.                                    ))
  601.                                    (:TYPE
  602.                                     (when types
  603.                                       (error #+DEUTSCH "~S ~S, Slot-Option ~S zu Slot ~S darf nur einmal angegeben werden."
  604.                                              #+ENGLISH "~S ~S, slot option ~S for slot ~S may only be given once"
  605.                                              'defclass name ':type slot-name
  606.                                     ) )
  607.                                     (setq types (list argument))
  608.                                    )
  609.                                    (:DOCUMENTATION
  610.                                     (when documentation
  611.                                       (error #+DEUTSCH "~S ~S, Slot-Option ~S zu Slot ~S darf nur einmal angegeben werden."
  612.                                              #+ENGLISH "~S ~S, slot option ~S for slot ~S may only be given once"
  613.                                              'defclass name ':documentation slot-name
  614.                                     ) )
  615.                                     (unless (stringp argument)
  616.                                       (error #+DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist kein String."
  617.                                              #+ENGLISH "~S ~S, slot option for slot ~S: ~S is not a string"
  618.                                              'defclass name slot-name argument
  619.                                     ) )
  620.                                     (setq documentation argument)
  621.                                    )
  622.                                    (t
  623.                                      (error #+DEUTSCH "~S ~S, Slot-Option zu Slot ~S: ~S ist keine gültige Slot-Option."
  624.                                             #+ENGLISH "~S ~S, slot option for slot ~S: ~S is not a valid slot option"
  625.                                             'defclass name slot-name optionkey
  626.                                    ) )
  627.                              ) ) )
  628.                              (setq readers (nreverse readers))
  629.                              (setq writers (nreverse writers))
  630.                              (dolist (funname readers)
  631.                                (push `(DEFMETHOD ,funname ((OBJECT ,name))
  632.                                         (SLOT-VALUE OBJECT ',slot-name)
  633.                                       )
  634.                                      accessor-def-forms
  635.                              ) )
  636.                              (dolist (funname writers)
  637.                                (push `(DEFMETHOD ,funname (NEW-VALUE (OBJECT ,name))
  638.                                         (SETF (SLOT-VALUE OBJECT ',slot-name) NEW-VALUE)
  639.                                       )
  640.                                      accessor-def-forms
  641.                              ) )
  642.                              `(LIST
  643.                                 :NAME ',slot-name
  644.                                 ,@(when accessors `(:ACCESSORS ',(nreverse accessors)))
  645.                                 ,@(when readers `(:READERS ',readers))
  646.                                 ,@(when writers `(:WRITERS ',writers))
  647.                                 ,@(when (eq allocation ':class) `(:ALLOCATION :CLASS))
  648.                                 ,@(when initargs `(:INITARGS ',(nreverse initargs)))
  649.                                 ,@(when initform `(#| :INITFORM ,initform |# :INITER ,initer))
  650.                                 ,@(when types `(:TYPE ',(first types)))
  651.                                 ,@(when documentation `(:DOCUMENTATION ',documentation))
  652.                               )
  653.                        ) ) )
  654.                      slot-specs
  655.         )) ) )
  656.     `(LET ()
  657.        (EVAL-WHEN (COMPILE LOAD EVAL)
  658.          (ENSURE-CLASS
  659.            ',name
  660.            :DIRECT-SUPERCLASSES (LIST ,@superclass-forms)
  661.            :DIRECT-SLOTS (LIST ,@slot-forms)
  662.            ,@(let ((metaclass nil)
  663.                    (direct-default-initargs nil)
  664.                    (documentation nil))
  665.                (dolist (option options)
  666.                  (block nil
  667.                    (when (and (listp option) (eql (length option) 2))
  668.                      (let ((optionkey (first option)))
  669.                        (when (case optionkey
  670.                                (:METACLASS metaclass)
  671.                                (:DEFAULT-INITARGS direct-default-initargs)
  672.                                (:DOCUMENTATION documentation)
  673.                              )
  674.                          (error #+DEUTSCH "~S ~S, Option ~S darf nur einmal angegeben werden."
  675.                                 #+ENGLISH "~S ~S, option ~S may only be given once"
  676.                                 'defclass name optionkey
  677.                        ) )
  678.                        (case optionkey
  679.                          (:METACLASS
  680.                           (let ((argument (second option)))
  681.                             (unless (symbolp argument)
  682.                               (error #+DEUTSCH "~S ~S, Option ~S: ~S ist kein Symbol."
  683.                                      #+ENGLISH "~S ~S, option ~S: ~S is not a symbol"
  684.                                      'defclass name option argument
  685.                             ) )
  686.                             (setq metaclass `(:METACLASS (FIND-CLASS ',argument)))
  687.                           )
  688.                            (return)
  689.                          )
  690.                          (:DEFAULT-INITARGS
  691.                           (let ((list (second option)))
  692.                             (when (oddp (length list))
  693.                               (error #+DEUTSCH "~S ~S, Option ~S: Argumente sind nicht paarig."
  694.                                      #+ENGLISH "~S ~S, option ~S: arguments don't come in pairs"
  695.                                      'defclass name option
  696.                             ) )
  697.                             (setq direct-default-initargs
  698.                                   `(:DIRECT-DEFAULT-INITARGS
  699.                                     (LIST
  700.                                      ,@(let ((arglist nil) (formlist nil))
  701.                                          (do ((list list (cddr list)))
  702.                                              ((atom list))
  703.                                            (unless (symbolp (first list))
  704.                                              (error #+DEUTSCH "~S ~S, Option ~S: ~S ist kein Symbol."
  705.                                                     #+ENGLISH "~S ~S, option ~S: ~S is not a symbol"
  706.                                                     'defclass name option (first list)
  707.                                            ) )
  708.                                            (when (member (first list) arglist)
  709.                                              (error #+DEUTSCH "~S ~S, Option ~S: ~S darf nur einmal angegeben werden."
  710.                                                     #+ENGLISH "~S ~S, option ~S: ~S may only be given once"
  711.                                                     'defclass name option (first list)
  712.                                            ) )
  713.                                            (push (first list) arglist)
  714.                                            (push (second list) formlist)
  715.                                          )
  716.                                          (mapcan #'(lambda (arg form)
  717.                                                      `(',arg ,(make-initer form))
  718.                                                    )
  719.                                                  (nreverse arglist) (nreverse formlist)
  720.                                        ) )
  721.                                    ))
  722.                           ) )
  723.                           (return)
  724.                          )
  725.                          (:DOCUMENTATION
  726.                           (let ((argument (second option)))
  727.                             (unless (stringp argument)
  728.                               (error #+DEUTSCH "~S ~S, Option ~S: ~S ist kein String."
  729.                                      #+ENGLISH "~S ~S, option ~S: ~S is not a string"
  730.                                      'defclass name option argument
  731.                             ) )
  732.                             (setq documentation `(:DOCUMENTATION ',argument))
  733.                           )
  734.                           (return)
  735.                          )
  736.                    ) ) )
  737.                    (error #+DEUTSCH "~S ~S: Ungültige Option ~S"
  738.                           #+ENGLISH "~S ~S: invalid option ~S"
  739.                           'defclass name option
  740.                ) ) )
  741.                `(,@metaclass ,@direct-default-initargs ,@documentation)
  742.              )
  743.        ) )
  744.        ,@(nreverse accessor-def-forms) ; die DEFMETHODs
  745.        (FIND-CLASS ',name)
  746.      )
  747. ) )
  748. ; Ein Initer zur Laufzeit ist - um Funktionsaufrufe zu sparen -
  749. ; i.a. ein Cons (init-function . nil), bei Konstanten aber (nil . init-value).
  750. (defun make-initer (form)
  751.   (if (constantp form)
  752.     `(CONS 'NIL ,form)
  753.     `(CONS (FUNCTION (LAMBDA () ,form)) 'NIL)
  754. ) )
  755.  
  756. ; DEFCLASS-Ausführung:
  757.  
  758. ; Zur Laufzeit noch bedeutsame Information eines Slots:
  759. (defstruct (slot-definition
  760.             (:conc-name "SLOTDEF-")
  761.             (:type vector) (:predicate nil)
  762.             (:constructor make-slot-definition (name allocation initargs location initer)))
  763.   (name nil :type symbol)
  764.   (allocation :instance :type (or (member :class :instance) class))
  765.   (initargs '() :type list)
  766.   (location nil :type (or null integer cons))
  767.   (initer nil :type (or null cons))
  768. )
  769.  
  770. (defun make-slotdef (&key name (allocation ':instance) (initargs '()) location (initer nil) (initform nil) (accessors '()) (readers '()) (writers '()) type documentation)
  771.   (declare (ignore initform accessors readers writers type documentation))
  772.   (make-slot-definition name allocation initargs location initer)
  773. )
  774.  
  775. (defun ensure-class (name &rest all-keys
  776.                           &key (metaclass <standard-class>)
  777.                                (direct-superclasses '())
  778.                                (direct-slots '())
  779.                                (direct-default-initargs '())
  780.                                (documentation nil)
  781.                           &allow-other-keys
  782.                     )
  783.   (let ((class (find-class name nil)))
  784.     (if class
  785.       ; Die einzige Modifikationen, die wir bei Klassen zulassen, sind die,
  786.       ; die bei doppeltem Laden desselben Codes auftreten können:
  787.       ; veränderte Slot-Optionen :initform, :documentation,
  788.       ; veränderte Klassen-Optionen :default-initargs, :documentation.
  789.       (if (and (eq metaclass <standard-class>)
  790.                (eq metaclass (class-of class))
  791.                (equal direct-superclasses (class-direct-superclasses class))
  792.                (equal-slots direct-slots (class-direct-slots class))
  793.                (equal-default-initargs direct-default-initargs (class-direct-default-initargs class))
  794.           )
  795.         (progn
  796.           ; neue Slot-Inits eintragen:
  797.           (do ((l-old (class-direct-slots class) (cdr l-old))
  798.                (l-new direct-slots (cdr l-new)))
  799.               ((null l-new))
  800.             (let ((old (getf (car l-old) ':initer))
  801.                   (new (getf (car l-new) ':initer)))
  802.               (when old
  803.                 ; Slot-Initer new destruktiv in den Slot-Initer old umfüllen:
  804.                 (setf (car old) (car new))
  805.                 (setf (cdr old) (cdr new))
  806.           ) ) )
  807.           ; neue Default-Initargs eintragen:
  808.           (do ((l-old (class-direct-default-initargs class) (cddr l-old))
  809.                (l-new direct-default-initargs (cddr l-new)))
  810.               ((null l-new))
  811.             (let ((old (second l-old))
  812.                   (new (second l-new)))
  813.               ; Initer new destruktiv in den Initer old umfüllen:
  814.               (setf (car old) (car new))
  815.               (setf (cdr old) (cdr new))
  816.           ) )
  817.           ; NB: Diese Modifikationen vererben sich auch automatisch auf die
  818.           ; Unterklassen von class!
  819.           ; neue Dokumentation eintragen:
  820.           (when documentation (setf (documentation name 'TYPE) documentation))
  821.           ; modifizierte Klasse als Wert:
  822.           class
  823.         )
  824.         (error #+DEUTSCH "~S: Klasse ~S kann nicht umdefiniert werden."
  825.                #+ENGLISH "~S: Cannot redefine class ~S"
  826.                'defclass name
  827.       ) )
  828.       (progn
  829.         (when documentation (setf (documentation name 'TYPE) documentation))
  830.         (setf (find-class name)
  831.               (apply (cond ((eq metaclass <standard-class>) #'make-instance-standard-class)
  832.                            ((eq metaclass <built-in-class>) #'make-instance-built-in-class) ; ??
  833.                            ((eq metaclass <structure-class>) #'make-instance-structure-class)
  834.                            (t #'make-instance)
  835.                      )
  836.                      metaclass
  837.                      :name name
  838.                      all-keys
  839.       ) )     )
  840. ) ) )
  841. (defun equal-slots (slots1 slots2)
  842.   (or (and (null slots1) (null slots2))
  843.       (and (consp slots1) (consp slots2)
  844.            (equal-slot (first slots1) (first slots2))
  845.            (equal-slots (rest slots1) (rest slots2))
  846. ) )   )
  847. (defun equal-slot (slot1 slot2) ; slot1, slot2 Plisten
  848.   (or (and (null slot1) (null slot2))
  849.       (and #| (consp slot1) (consp slot2) |#
  850.            (eq (first slot1) (first slot2))
  851.            (or (memq (first slot1) '(#| :initform |# :initer #| :documentation |# ))
  852.                (equal (second slot1) (second slot2))
  853.            )
  854.            (equal-slot (cddr slot1) (cddr slot2))
  855. ) )   )
  856. (defun equal-default-initargs (initargs1 initargs2)
  857.   (or (and (null initargs1) (null initargs2))
  858.       (and (consp initargs1) (consp initargs2)
  859.            (eq (first initargs1) (first initargs2))
  860.            (equal-default-initargs (cddr initargs1) (cddr initargs2))
  861. ) )   )
  862.  
  863. ; Erzeugung einer Instanz von <standard-class>:
  864.  
  865. (let (unbound) (declare (compile)) ; unbound = #<unbound>
  866. (defun def-unbound (x) (declare (compile)) (setq unbound x))
  867. (defun make-instance-standard-class
  868.        (metaclass &key name (direct-superclasses '()) (direct-slots '())
  869.                             (direct-default-initargs '())
  870.                   &allow-other-keys
  871.        )
  872.   ; metaclass = <standard-class>
  873.   (unless (every #'standard-class-p direct-superclasses)
  874.     (error #+DEUTSCH "~S ~S: Oberklasse ~S sollte zur Klasse STANDARD-CLASS gehören."
  875.            #+ENGLISH "~S ~S: superclass ~S should belong to class STANDARD-CLASS"
  876.            'defclass name (find-if-not #'standard-class-p direct-superclasses)
  877.   ) )
  878.   (let ((class (make-standard-class :classname name :metaclass metaclass)))
  879.     (setf (class-direct-superclasses class) (copy-list direct-superclasses))
  880.     (setf (class-precedence-list class)
  881.           (std-compute-cpl class `(,@direct-superclasses ,<standard-object>))
  882.     )
  883.     (setf (class-all-superclasses class)
  884.           (std-compute-superclasses (class-precedence-list class))
  885.     )
  886.     (setf (class-direct-slots class) direct-slots)
  887.     (setf (class-slots class) (std-compute-slots class))
  888.     (let ((ht (make-hash-table :test #'eq))
  889.           (local-index 1) ; Index 0 wird von der Klasse belegt
  890.           (shared-index 0))
  891.       (mapc #'(lambda (slot)
  892.                 (let* ((name (slotdef-name slot))
  893.                        (allocation (slotdef-allocation slot))
  894.                        (location
  895.                          (cond ((eq allocation ':instance) ; local slot
  896.                                 (prog1 local-index (incf local-index))
  897.                                )
  898.                                ((eq allocation class) ; new shared slot
  899.                                 (prog1 (cons class shared-index) (incf shared-index))
  900.                                )
  901.                                (t ; inherited shared slot
  902.                                 (gethash name (class-slot-location-table allocation))
  903.                       )) )     )
  904.                   (setf (slotdef-location slot) location)
  905.                   (setf (gethash name ht) location)
  906.               ) )
  907.             (class-slots class)
  908.       )
  909.       (setf (class-slot-location-table class) ht)
  910.       (setf (class-instance-slot-count class) local-index)
  911.       (when (plusp shared-index)
  912.         (setf (class-shared-slots class)
  913.               (let ((v (make-array shared-index))
  914.                     (i 0))
  915.                 (mapc #'(lambda (slot)
  916.                           (when (eq (slotdef-allocation slot) class)
  917.                             (setf (svref v i)
  918.                               (let ((init (slotdef-initer slot)))
  919.                                 (if init
  920.                                   (if (car init) (funcall (car init)) (cdr init))
  921.                                   unbound
  922.                             ) ) )
  923.                             (incf i)
  924.                         ) )
  925.                       (class-slots class)
  926.                 )
  927.                 v
  928.       ) )     )
  929.     )
  930.     (setf (class-direct-default-initargs class) direct-default-initargs)
  931.     (setf (class-default-initargs class) ; 28.1.3.3.
  932.           (remove-duplicates
  933.             (mapcan
  934.               #'(lambda (c)
  935.                   (when (standard-class-p c)
  936.                     (plist-to-alist (class-direct-default-initargs c))
  937.                 ) )
  938.               (class-precedence-list class)
  939.             )
  940.             :key #'car
  941.             :from-end t
  942.     )     )
  943.     (setf (class-valid-initargs class)
  944.           (remove-duplicates (mapcap #'slotdef-initargs (class-slots class)))
  945.     )
  946.     class
  947. ) )
  948. ) ; let
  949.  
  950. ;; 28.1.5. Determining the Class Precedence List
  951. ;
  952. ; Die Menge aller Klassen bildet einen gerichteten Graphen: Klasse C sitzt
  953. ; unterhalb der direkten Oberklassen von C. Dieser Graph ist azyklisch, weil
  954. ; zum Zeitpunkt Definition der Klasse C alle direkten Oberklassen bereits
  955. ; vorhanden sein müssen.
  956. ;
  957. ; Man kann daher noethersche Induktion (Induktion von oben nach unten im
  958. ; Klassengraphen) verwenden.
  959. ;
  960. ; Zu einer Klasse C sei DS(n) die Liste aller direkten Oberklassen von C.
  961. ; Die Menge aller Oberklassen (inkl. C selbst) ist induktiv definiert als
  962. ; S(C) := {C} union union_{D in DS(C)} S(D).
  963. ;
  964. ; Anders ausgedrückt:
  965. ; S(C) = { C_n : C_n in DS(C_{n-1}), ..., C_1 in DS(C_0), C_0 = C }
  966. ;
  967. ; Lemma 1: (a) C in S(C).
  968. ;          (b) DS(C) subset S(C).
  969. ;          (c) D in DS(C) ==> S(D) subset S(C).
  970. ;          (d) D in S(C) ==> S(D) subset S(C).
  971. ; Beweis: (a) Aus der Definition.
  972. ;         (b) Aus (a) und der Definition.
  973. ;         (c) Aus der Definition.
  974. ;         (d) Aus (c) bei festem D mit Induktion über C.
  975. ;
  976. ; Die CPL einer Klasse C ist eine Anordnung der Menge S(C).
  977. ; Falls CPL(C) = (... D1 ... D2 ...), schreibt man D1 < D2. Die so eingeführte
  978. ; Relation ist eine Totalordnung auf S(C).
  979. ; Dabei ist die folgende Menge von Restriktionen zu berücksichtigen:
  980. ; R(C) := union_{D in S(C)} DR(D)  mit
  981. ; DR(C) := { C < C1, C1 < C2, ..., C{n-1} < C_n } falls DS(C) = (C1, ..., Cn).
  982. ; Falls R(C) einen Zyklus enthält, kann natürlich R(C) nicht zu einer
  983. ; Totalordnung vervollständigt werden. Dann heißt R(C) inkonsistent.
  984. ; CPL(C) wird folgendermaßen konstruiert:
  985. ;   L := (), R := R(C).
  986. ;   L := (L | C), entferne alle (C < ..) aus R.
  987. ;   Solange R /= {}, betrachte die Menge M aller minimalen Elemente von R
  988. ;     (das sind diejenigen Klassen, die man, ohne R(C) zu verletzen, zu L
  989. ;     hinzufügen könnte). Ist M leer, so hat man einen Zyklus in R(C) und
  990. ;     bricht den Algorithmus ab. Sonst wähle unter den Elementen E von M
  991. ;     dasjenige aus, das ein möglichst weit rechts in L gelegenes D mit
  992. ;     E in DS(D) besitzt.
  993. ;     L := (L | E), entferne alle (E < ..) aus R.
  994. ;   CPL(C) := L.
  995. ; L wird schrittweise um ein Element verlängert, R wird schrittweise
  996. ; verkleinert, und R besteht immer nur aus Relationen zwischen Elementen
  997. ; von S(C)\L.
  998. ;
  999. ; Lemma 2: (a) CPL(C) = (C ...).
  1000. ;          (b) Ist DS(C) = (C1, ..., Cn), so ist
  1001. ;              CPL(C) = (C ... C1 ... C2 ... ... Cn ...).
  1002. ; Beweis: (a) Klar nach Konstruktion.
  1003. ;         (b) Wenn Ci in die CPL aufgenommen wird, kann die Restriktion
  1004. ;             C{i-1} < Ci nicht mehr in R sein, also muß C{i-1} schon in
  1005. ;             der CPL sein.
  1006. ;
  1007. ; Folgende Aussage ist falsch:
  1008. ; (*) Ist D in DS(C) und CPL(D) = (D1, ..., Dn), so ist
  1009. ;     CPL(C) = (C ... D1 ... D2 ... ... Dn ...).
  1010. ; Beispiel:
  1011. ;     z
  1012. ;    /|\             CPL(z) = (z)
  1013. ;   / | \            CPL(x) = (x z)
  1014. ;  x  |  x           CPL(y) = (y z)
  1015. ;  |  |  |           CPL(d) = (d x z)
  1016. ;  d  y  e           CPL(e) = (e x z)
  1017. ;   \/ \/            CPL(b) = (b d x y z)
  1018. ;   b   c            CPL(c) = (c y e x z)
  1019. ;    \ /             CPL(a) = (a b d c y e x z)
  1020. ;     a
  1021. ;                    CPL(a) enthält CPL(b) nicht!
  1022. ;
  1023. #|
  1024. (defclass z () ())
  1025. (defclass x (z) ())
  1026. (defclass y (z) ())
  1027. (defclass d (x z) ())
  1028. (defclass e (x z) ())
  1029. (defclass b (d y) ())
  1030. (defclass c (y e) ())
  1031. (defclass a (b c) ())
  1032. (mapcar #'find-class '(z x y d e b c a))
  1033. |#
  1034.  
  1035. (defun std-compute-cpl (class direct-superclasses)
  1036.   (let* ((superclasses ; Liste aller Oberklassen in irgendeiner Reihenfolge
  1037.            (remove-duplicates
  1038.              (mapcap #'class-precedence-list direct-superclasses)
  1039.          ) )
  1040.          (L '())
  1041.          (R1 (list (cons class direct-superclasses)))
  1042.          (R2 (mapcar #'(lambda (D) (cons D (class-direct-superclasses D)))
  1043.                      superclasses
  1044.         ))   )
  1045.     (loop
  1046.       ; L ist die umgedrehte bisher konstruierte CPL.
  1047.       ; R1 ist die Liste der bisher relevanten Restriktionen, in der Form
  1048.       ; R1 = (... (Dj ... Dn) ...) wenn aus DR(D) = (D1 ... Dn) nur noch
  1049.       ; Dj,...,Dn übrig sind. Die Reihenfolge in R1 entspricht der in L.
  1050.       ; R2 ist die Liste der bisher irrelevanten Restriktionen.
  1051.       (when (null R1)
  1052.         (return) ; R1 = R2 = () -> fertig
  1053.       )
  1054.       (let ((M (remove-duplicates (mapcar #'first R1) :from-end t)))
  1055.         (setq M
  1056.           (remove-if
  1057.             #'(lambda (E)
  1058.                 (or (dolist (r R1 nil) (when (member E (cdr r)) (return t)))
  1059.                     (dolist (r R2 nil) (when (member E (cdr r)) (return t)))
  1060.               ) )
  1061.             M
  1062.         ) )
  1063.         (when (null M)
  1064.           (error #+DEUTSCH "~S ~S: Inkonsistenter Präzedenz-Graph, Zyklus ~S"
  1065.                  #+ENGLISH "~S ~S: inconsistent precedence graph, cycle ~S"
  1066.                  'defclass (class-classname class)
  1067.                  ; Zyklus finden: mit Hilfe der Restriktionen zu immer
  1068.                  ; kleineren Elementen voranschreiten.
  1069.                  (let* ((R0 (append R1 R2))
  1070.                         (cycle (list (car (first R0)))))
  1071.                    (loop
  1072.                      (let* ((last (car cycle))
  1073.                             (next (dolist (r R0 nil)
  1074.                                     (when (member last (cdr r))
  1075.                                       (return (nth (position last (cdr r)) r))
  1076.                            ))     ) )
  1077.                        (when (null next)
  1078.                          ; Offenbar ist last nun doch ein minimales Element!
  1079.                          (return '??)
  1080.                        )
  1081.                        (when (member next cycle)
  1082.                          (setf (cdr (member next cycle)) nil)
  1083.                          (return cycle)
  1084.                        )
  1085.                        (push next cycle)
  1086.                  ) ) )
  1087.         ) )
  1088.         (let ((E (first M)))
  1089.           (push E L)
  1090.           (push (assoc E R2) R1)
  1091.           (setq R2 (delete E R2 :key #'first))
  1092.           (mapl #'(lambda (r) (when (eq (first (car r)) E) (pop (car r)))) R1)
  1093.           (setq R1 (delete-if #'null R1))
  1094.     ) ) )
  1095.     (setq L (nreverse L))
  1096.     ; Teste, ob L mit den CPL(D), D in direct-superclasses, verträglich ist:
  1097.     (mapc #'(lambda (D)
  1098.               (unless ; Ist (class-precedence-list D) Teil-Liste von L ?
  1099.                 (do ((CL L)
  1100.                      (DL (class-precedence-list D) (cdr DL)))
  1101.                     ((null DL) t)
  1102.                   (when (null (setq CL (member (car DL) CL))) (return nil))
  1103.                 )
  1104.                 (warn #+DEUTSCH "(class-precedence-list ~S) und (class-precedence-list ~S) sind nicht verträglich."
  1105.                       #+ENGLISH "(class-precedence-list ~S) and (class-precedence-list ~S) are inconsistent"
  1106.                       class D
  1107.             ) ) )
  1108.           direct-superclasses
  1109.     )
  1110.     L
  1111. ) )
  1112.  
  1113. ; Stopft alle Oberklassen (aus der precedence-list) in eine Hash-Tabelle.
  1114. (defun std-compute-superclasses (precedence-list)
  1115.   (let ((ht (make-hash-table :test #'eq)))
  1116.     (mapc #'(lambda (superclass) (setf (gethash superclass ht) t))
  1117.           precedence-list
  1118.     )
  1119.     ht
  1120. ) )
  1121.  
  1122. ; Hilfsfunktion (p1 v1 ... pn vn) -> ((p1 . v1) ... (pn . vn))
  1123. (defun plist-to-alist (pl &aux (al '()))
  1124.   (loop
  1125.     (when (null pl) (return))
  1126.     (setq al (acons (first pl) (second pl) al))
  1127.     (setq pl (cddr pl))
  1128.   )
  1129.   (nreverse al)
  1130. )
  1131.  
  1132. ; Hilfsfunktion ((p1 . v1) ... (pn . vn)) -> (p1 v1 ... pn vn)
  1133. (defun alist-to-plist (al)
  1134.   (mapcan #'(lambda (pv) (list (car pv) (cdr pv))) al)
  1135. )
  1136.  
  1137. ;; 28.1.3.2. Inheritance of Slots and Slot Options
  1138.  
  1139. (defun std-compute-slots (class)
  1140.   ; Alle Slot-Specifier sammeln, geordnet nach Präzedenz:
  1141.   (let ((all-slots
  1142.           (mapcan
  1143.             #'(lambda (c)
  1144.                 (if (standard-class-p c)
  1145.                   (mapcar #'(lambda (slot)
  1146.                               (setq slot (plist-to-alist slot))
  1147.                               (when (eq (cdr (assoc ':allocation slot)) ':class)
  1148.                                 (setf (cdr (assoc ':allocation slot)) c)
  1149.                               )
  1150.                               slot
  1151.                             )
  1152.                     (class-direct-slots c)
  1153.               ) ) )
  1154.             (class-precedence-list class)
  1155.        )) )
  1156.     ; Aufspalten nach Slot-Namen:
  1157.     (setq all-slots
  1158.       (let ((ht (make-hash-table :test #'eq)))
  1159.         (dolist (slot all-slots)
  1160.           (assert (eq (caar slot) ':name))
  1161.           (push (cdr slot) (gethash (cdar slot) ht nil))
  1162.         )
  1163.         (let ((L nil))
  1164.           (maphash #'(lambda (name slots) (push (cons name (nreverse slots)) L)) ht)
  1165.           L ; nicht (nreverse L), da maphash die Reihenfolge umdreht
  1166.     ) ) )
  1167.     ; all-slots ist nun eine Liste von Listen der Form
  1168.     ; (name most-specific-slotspec ... least-specific-slotspec).
  1169.     (mapcar #'(lambda (slot)
  1170.                 (let ((name (car slot))
  1171.                       (slotspecs (cdr slot)))
  1172.                   (apply #'make-slotdef
  1173.                     :name name
  1174.                     (alist-to-plist
  1175.                       `(,(or (assoc ':allocation (first slotspecs))
  1176.                              `(:allocation . :instance)
  1177.                          )
  1178.                         #|
  1179.                         ,@(let ((accessors
  1180.                                   (mapcap #'(lambda (slotspec) (cdr (assoc ':accessors slotspec)))
  1181.                                           slotspecs
  1182.                                )) )
  1183.                             (if accessors `((:accessors . ,accessors)))
  1184.                           )
  1185.                         |#
  1186.                         ,@(let ((initargs
  1187.                                   (remove-duplicates
  1188.                                     (mapcap #'(lambda (slotspec) (cdr (assoc ':initargs slotspec)))
  1189.                                             slotspecs
  1190.                                     )
  1191.                                     :from-end t
  1192.                                )) )
  1193.                             (if initargs `((:initargs . ,initargs)))
  1194.                           )
  1195.                         ,@(dolist (slotspec slotspecs '())
  1196.                             (when (assoc ':initer slotspec)
  1197.                               (return `(#| ,(assoc ':initform slotspec) |# ,(assoc ':initer slotspec)))
  1198.                           ) )
  1199.                         #|
  1200.                         ,(let ((types '()))
  1201.                            (dolist (slotspec slotspecs)
  1202.                              (when (assoc ':type slotspec)
  1203.                                (push (cdr (assoc ':type slotspec)) types)
  1204.                            ) )
  1205.                            `(:type . ,(if types `(AND ,@(nreverse types)) 'T))
  1206.                          )
  1207.                         |#
  1208.                         #|
  1209.                         ,@(dolist (slotspec slotspecs '())
  1210.                             (when (assoc ':documentation slotspec)
  1211.                               (return `(,(assoc ':documentation slotspec)))
  1212.                           ) )
  1213.                         |#
  1214.                        )
  1215.               ) ) ) )
  1216.             all-slots
  1217.     )
  1218. ) )
  1219.  
  1220.  
  1221. ; Erzeugung einer Instanz von <built-in-class>:
  1222.  
  1223. (defun make-instance-built-in-class
  1224.        (metaclass &key name (direct-superclasses '())
  1225.                   &allow-other-keys
  1226.        )
  1227.   ; metaclass = <built-in-class>
  1228.   (unless (every #'built-in-class-p direct-superclasses)
  1229.     (error #+DEUTSCH "~S: Oberklasse ~S sollte zur Klasse BUILT-IN-CLASS gehören."
  1230.            #+ENGLISH "~S: superclass ~S should belong to class BUILT-IN-CLASS"
  1231.            name (find-if-not #'built-in-class-p direct-superclasses)
  1232.   ) )
  1233.   (let ((class (make-built-in-class :classname name :metaclass metaclass)))
  1234.     (setf (class-direct-superclasses class) (copy-list direct-superclasses))
  1235.     (setf (class-precedence-list class)
  1236.           (std-compute-cpl class direct-superclasses)
  1237.     )
  1238.     (setf (class-all-superclasses class)
  1239.           (std-compute-superclasses (class-precedence-list class))
  1240.     )
  1241.     class
  1242. ) )
  1243.  
  1244.  
  1245. ; Erzeugung einer Instanz von <structure-class>:
  1246.  
  1247. (defun make-instance-structure-class
  1248.        (metaclass &key name (direct-superclasses '()) (slots '())
  1249.                   &allow-other-keys
  1250.        )
  1251.   ; metaclass = <structure-class>
  1252.   (unless (null (cdr direct-superclasses))
  1253.     (error #+DEUTSCH "~S: Metaklasse STRUCTURE-CLASS läßt nur eine direkte Oberklasse zu."
  1254.            #+ENGLISH "~S: metaclass STRUCTURE-CLASS forbids more than one direct superclass"
  1255.            name
  1256.   ) )
  1257.   (unless (every #'structure-class-p direct-superclasses)
  1258.     (error #+DEUTSCH "~S: Oberklasse ~S sollte zur Klasse STRUCTURE-CLASS gehören."
  1259.            #+ENGLISH "~S: superclass ~S should belong to class STRUCTURE-CLASS"
  1260.            name (first direct-superclasses)
  1261.   ) )
  1262.   (let ((class (make-structure-class :classname name :metaclass metaclass)))
  1263.     (setf (class-direct-superclasses class) (copy-list direct-superclasses))
  1264.     (setf (class-precedence-list class)
  1265.           (std-compute-cpl class `(,@direct-superclasses ,<t>))
  1266.     )
  1267.     (setf (class-all-superclasses class)
  1268.           (std-compute-superclasses (class-precedence-list class))
  1269.     )
  1270.     (setf (class-slot-location-table class)
  1271.           (make-hash-table :test #'eq :initial-contents slots)
  1272.     )
  1273.     class
  1274. ) )
  1275.  
  1276. ; DEFSTRUCT-Hook
  1277. (defun define-structure-class (name)
  1278.   (let ((descr (get name 'sys::defstruct-description)))
  1279.     (when descr
  1280.       (let ((names (svref descr 0)))
  1281.         (setf (find-class name)
  1282.               (make-instance-structure-class <structure-class>
  1283.                 :name name
  1284.                 :direct-superclasses
  1285.                   (if (cdr names) (list (find-class (second names))) '())
  1286.                 :slots
  1287.                   (mapcan #'(lambda (slot)
  1288.                               (if (first slot)
  1289.                                 (list (cons (first slot) (second slot)))
  1290.                             ) )
  1291.                           (svref descr 3)
  1292.                   )
  1293. ) ) ) ) )     )
  1294.  
  1295. ;; Bootstrapping
  1296. (progn
  1297.   ; 1. Klasse <t>
  1298.   (setq <t>
  1299.         (make-instance-built-in-class nil :name 't :direct-superclasses '())
  1300.   )
  1301.   ; 2. Klasse <structure-class>
  1302.   (setq <structure-class> (make-structure-class)) ; Dummy, damit (setf find-class) geht
  1303.   (let ((<class> (define-structure-class 'class)))
  1304.     (setq <structure-class> (define-structure-class 'structure-class))
  1305.     (setf (class-metaclass <class>) <structure-class>)
  1306.     (setf (class-metaclass <structure-class>) <structure-class>)
  1307.   )
  1308.   ; 3. Alle structure-Klassen
  1309.   (labels ((define-structure-class-with-includes (name)
  1310.              (when (get name 'sys::defstruct-description)
  1311.                (unless (find-class name nil)
  1312.                  (let ((names (svref (get name 'sys::defstruct-description) 0)))
  1313.                    (when (cdr names)
  1314.                      (define-structure-class-with-includes (second names))
  1315.                  ) )
  1316.                  (define-structure-class name)
  1317.           )) ) )
  1318.     (do-all-symbols (s) (define-structure-class-with-includes s))
  1319.   )
  1320.   ; 4. Klassen <standard-class>, <built-in-class>
  1321.   (setq <standard-class> (find-class 'standard-class))
  1322.   (setq <built-in-class> (find-class 'built-in-class))
  1323.   ; 5. Klasse <t> zu Ende
  1324.   (setf (class-metaclass <t>) <built-in-class>)
  1325.   (setf (find-class 't) <t>)
  1326.   ; 6. Klasse <standard-object>
  1327.   (setq <standard-object>
  1328.         (make-standard-class
  1329.           :classname 'standard-object
  1330.           :metaclass <standard-class>
  1331.           :direct-superclasses `(,<t>)
  1332.           :direct-slots '()
  1333.           :slots '()
  1334.           :slot-location-table empty-ht
  1335.           :instance-slot-count 1
  1336.           :direct-default-initargs nil
  1337.           :default-initargs nil
  1338.   )     )
  1339.   (setf (class-all-superclasses <standard-object>)
  1340.         (std-compute-superclasses
  1341.           (setf (class-precedence-list <standard-object>)
  1342.                 `(,<standard-object> ,<t>)
  1343.   )     ) )
  1344.   (setf (find-class 'standard-object) <standard-object>)
  1345.   ; 7. Wert #<unbound>
  1346.   (def-unbound
  1347.     (sys::%record-ref (allocate-std-instance <standard-object> 2) 1)
  1348.   )
  1349. )
  1350.  
  1351.  
  1352. ;; 28.1.4. Integrating Types and Classes
  1353. (defun subclassp (class1 class2)
  1354.   (gethash class2 (class-all-superclasses class1)) ; T oder (Default) NIL
  1355. )
  1356.  
  1357. ;; Built-In-Klassen installieren
  1358. ; Table 28-1, CLtL2 p. 783
  1359. (macrolet ((def (&rest classes &aux (new (car (last classes))))
  1360.              (let ((name (intern (string-trim "<>" (symbol-name new)))))
  1361.                `(setf (find-class ',name)
  1362.                   (setq ,new
  1363.                     (make-instance-built-in-class <built-in-class>
  1364.                       :name ',name
  1365.                       :direct-superclasses (list ,@(cdr (reverse classes)))
  1366.                 ) ) )
  1367.           )) )
  1368.  ;(def <t>)
  1369.   (def <t> <character>)
  1370.   (def <t> <function>)
  1371.   (def     <function> <standard-generic-function>)
  1372.   (def <t> <hash-table>)
  1373.   (def <t> <package>)
  1374.   (def <t> <pathname>)
  1375.   (def <t> <random-state>)
  1376.   (def <t> <readtable>)
  1377.   (def <t> <stream>)
  1378.   (def <t> <symbol>)
  1379.   (def <t> <sequence>)
  1380.   (def     <sequence> <list>)
  1381.   (def                <list> <cons>)
  1382.   (def                <list> <symbol> <null>)
  1383.   (def <t>            <array>)
  1384.   (def     <sequence> <array> <vector>)
  1385.   (def                        <vector> <bit-vector>)
  1386.   (def                        <vector> <string>)
  1387.   (def <t> <number>)
  1388.   (def     <number> <complex>)
  1389.   (def     <number> <real>)
  1390.   (def              <real> <float>)
  1391.   (def              <real> <rational>)
  1392.   (def                     <rational> <ratio>)
  1393.   (def                     <rational> <integer>)
  1394. )
  1395.  
  1396. ; Weiter Bootstrapping
  1397. (%defclos
  1398.   ; Erkennungszeichen für CLASS-P
  1399.   (svref (get 'class 'sys::defstruct-description) 0)
  1400.   ; Built-In-Klassen für CLASS-OF
  1401.   (vector <array> <bit-vector> <character> <complex> <cons> <float> <function>
  1402.           <hash-table> <integer> <null> <package> <pathname> <random-state>
  1403.           <ratio> <readtable> <standard-generic-function> <stream> <string>
  1404.           <symbol> <t> <vector>
  1405. ) )
  1406.  
  1407. ;; Schnitt zweier Built-In-Klassen:
  1408. ; Abweichungen von der Single-Inheritance sind nur
  1409. ; (AND <sequence> <array>) = <vector> und (AND <list> <symbol>) = <null>.
  1410. (defun bc-p (class)
  1411.   (or (built-in-class-p class) (eq class <standard-object>))
  1412. )
  1413. (defun bc-and (class1 class2) ; liefert (AND class1 class2)
  1414.   (cond ((subclassp class1 class2) class1)
  1415.         ((subclassp class2 class1) class2)
  1416.         ((or (and (subclassp <sequence> class1) (subclassp <array> class2))
  1417.              (and (subclassp <sequence> class2) (subclassp <array> class1))
  1418.          )
  1419.          <vector>
  1420.         )
  1421.         ((or (and (subclassp <list> class1) (subclassp <symbol> class2))
  1422.              (and (subclassp <list> class2) (subclassp <symbol> class1))
  1423.          )
  1424.          <null>
  1425.         )
  1426.         (t nil)
  1427. ) )
  1428. (defun bc-and-not (class1 class2) ; liefert eine Klasse c mit
  1429.                                   ; (AND class1 (NOT class2)) <= c <= class1
  1430.   (cond ((subclassp class1 class2) nil)
  1431.         ((and (eq class1 <sequence>) (subclassp <vector> class2)) <list>)
  1432.         ((and (eq class1 <sequence>) (subclassp <list> class2)) <vector>)
  1433.         ((and (eq class1 <list>) (subclassp <null> class2)) <cons>)
  1434.         (t class1)
  1435. ) )
  1436.  
  1437.  
  1438. ;;; Methoden
  1439.  
  1440. (defstruct (standard-method (:conc-name "STD-METHOD-") (:print-function print-std-method))
  1441.   function               ; die Funktion
  1442.   wants-next-method-p    ; Flag, ob als erstes Argument die NEXT-METHOD (als
  1443.                          ; Funktion mit allen Argumenten) bzw. NIL übergeben
  1444.                          ; werden soll (= NIL bei :BEFORE- und :AFTER-Methoden)
  1445.   parameter-specializers ; Liste ({class | (EQL object)}*)
  1446.   qualifiers             ; Liste von Symbolen, z.B. (:before)
  1447.   signature              ; Liste (reqanz optanz restp keyp keywords allowp)
  1448.   gf                     ; die generische Funktion, zu der diese Methode
  1449.                          ; gehört (nur für den Bedarf von NO-NEXT-METHOD)
  1450.   initfunction           ; liefert, wenn aufgerufen, die Funktion
  1451.                          ; (nur für den Bedarf von ADD-METHOD)
  1452. )
  1453.  
  1454. ; Bei NO-NEXT-METHOD muß die generische Funktion bekannt sein. Da allerdings
  1455. ; im Prinzip Methoden nicht bestimmten generischen Funktionen zugehörig sind
  1456. ; (wegen ADD-METHOD), müssen wir die Methode bei ADD-METHOD kopieren. Die
  1457. ; Identität zweier Kopien derselben Methode stellen wir durch Blick auf
  1458. ; std-method-initfunction fest. (Man könnte stattdessen auch die generische
  1459. ; Funktion bei jedem Aufruf mitgeben, als erstes Argument an die effektive
  1460. ; Methode, aber das ist sicher ineffizienter.)
  1461.  
  1462. (defun print-std-method (method stream depth)
  1463.   (declare (ignore depth))
  1464.   (print-unreadable-object (method stream :type t)
  1465.     (dolist (q (std-method-qualifiers method))
  1466.       (write q :stream stream)
  1467.       (write-char #\Space stream)
  1468.     )
  1469.     (write (std-method-parameter-specializers method) :stream stream)
  1470. ) )
  1471.  
  1472. ; Hilfsfunktion: Liefert eine Liste von n Gensyms.
  1473. (defun n-gensyms (n)
  1474.   (do ((l '() (cons (gensym) l))
  1475.        (i n (1- i)))
  1476.       ((eql i 0) l)
  1477. ) )
  1478.  
  1479. ; Hilfsfunktion: Testet auf Lambda-Listen-Marker.
  1480. (defun lambda-list-keyword-p (x)
  1481.   (memq x lambda-list-keywords)
  1482. )
  1483.  
  1484. ;; Für DEFMETHOD, DEFGENERIC, GENERIC-FUNCTION, GENERIC-FLET, GENERIC-LABELS,
  1485. ;; WITH-ADDED-METHODS
  1486.   ; caller: Symbol
  1487.   ; funname: Funktionsname, Symbol oder (SETF symbol)
  1488.   ; description: (qualifier* spec-lambda-list {declaration|docstring}* form*)
  1489.   ; ==> method-building-form
  1490. (defun analyze-method-description (caller funname description env)
  1491.   (let ((qualifiers nil))
  1492.     (loop
  1493.       (when (atom description)
  1494.         (error #+DEUTSCH "~S ~S: Lambdaliste fehlt."
  1495.                #+ENGLISH "~S ~S: missing lambda list"
  1496.                caller funname
  1497.       ) )
  1498.       (when (listp (car description)) (return))
  1499.       (push (pop description) qualifiers)
  1500.     )
  1501.     ; Nur STANDARD Methodenkombination ist implementiert.
  1502.     (cond ((equal qualifiers '()))
  1503.           ((equal qualifiers '(:before)))
  1504.           ((equal qualifiers '(:after)))
  1505.           ((equal qualifiers '(:around)))
  1506.           (t (error #+DEUTSCH "Bei STANDARD Methodenkombination dürfen die Methodenbestimmer nicht ~S lauten."
  1507.                     #+ENGLISH "STANDARD method combination doesn't allow the method qualifiers to be ~S"
  1508.                     (nreverse qualifiers)
  1509.     )     )  )
  1510.     ; Lambdaliste bilden, Parameter-Specializer und Signatur extrahieren:
  1511.     (let ((specialized-lambda-list (car description))
  1512.           (body (cdr description)))
  1513.       (let ((req-vars '())
  1514.             (ignorable-req-vars '())
  1515.             (req-specializer-forms '()))
  1516.         (do ()
  1517.             ((or (atom specialized-lambda-list)
  1518.                  (lambda-list-keyword-p (car specialized-lambda-list))
  1519.             ))
  1520.           (let* ((item (pop specialized-lambda-list))
  1521.                  (specializer-name
  1522.                    (if (atom item)
  1523.                      (progn (push item req-vars) 't)
  1524.                      (progn
  1525.                        (push (first item) req-vars)
  1526.                        (push (first item) ignorable-req-vars) ; CLtL2 S. 840 oben
  1527.                        (second item)
  1528.                 )) ) )
  1529.             (push (if (and (consp specializer-name)
  1530.                            (eq (car specializer-name) 'EQL)
  1531.                       )
  1532.                     `(LIST 'EQL ,(second specializer-name))
  1533.                     `(FIND-CLASS ',specializer-name)
  1534.                   )
  1535.                   req-specializer-forms
  1536.         ) ) )
  1537.         (let* ((reqanz (length req-vars))
  1538.                (lambda-list (nreconc req-vars specialized-lambda-list))
  1539.                (optanz
  1540.                  (let ((h (cdr (member '&OPTIONAL lambda-list :test #'eq))))
  1541.                    (or (position-if #'lambda-list-keyword-p h) (length h))
  1542.                ) )
  1543.                (keyp (not (null (member '&KEY lambda-list :test #'eq))))
  1544.                (restp (or keyp (not (null (member '&REST lambda-list :test #'eq)))))
  1545.                (keywords
  1546.                  (mapcar
  1547.                    #'(lambda (item)
  1548.                        (when (consp item) (setq item (first item)))
  1549.                        (if (consp item)
  1550.                          (first item)
  1551.                          (intern (symbol-name item) *keyword-package*)
  1552.                      ) )
  1553.                    (let ((h (cdr (member '&KEY lambda-list :test #'eq))))
  1554.                      (subseq h 0 (position-if #'lambda-list-keyword-p h))
  1555.                ) ) )
  1556.                (allowp (and keyp (not (null (member '&ALLOW-OTHER-KEYS lambda-list :test #'eq)))))
  1557.               )
  1558.           ; Methoden haben ein implizites &allow-other-keys (28.1.6.4.):
  1559.           (when (and keyp (not allowp))
  1560.             (let ((index (+ (position '&KEY lambda-list :test #'eq) 1 (length keywords))))
  1561.               (setq lambda-list
  1562.                 `(,@(subseq lambda-list 0 index) &ALLOW-OTHER-KEYS
  1563.                   ,@(subseq lambda-list index)
  1564.                  )
  1565.           ) ) )
  1566.           (let* ((self (gensym))
  1567.                  (wants-next-method-p
  1568.                    (or (equal qualifiers '()) (equal qualifiers '(:around)))
  1569.                  )
  1570.                  (compile nil)
  1571.                  (lambdabody
  1572.                    (multiple-value-bind (body-rest declarations docstring)
  1573.                        (sys::parse-body body t env)
  1574.                      (declare (ignore docstring))
  1575.                      (setq compile (member '(COMPILE) declarations :test #'equal))
  1576.                      (when ignorable-req-vars
  1577.                        (push `(SYS::IGNORABLE ,@(nreverse ignorable-req-vars))
  1578.                              declarations
  1579.                      ) )
  1580.                      (let ((lambdabody-part1
  1581.                              `(,lambda-list
  1582.                                ,@(if declarations `((DECLARE ,@declarations)))
  1583.                               )
  1584.                            )
  1585.                            (lambdabody-part2
  1586.                              (if (eq caller 'generic-function)
  1587.                                body-rest
  1588.                                ; impliziter Block
  1589.                                `((BLOCK ,(block-name funname) ,@body-rest))
  1590.                           )) )
  1591.                        (if wants-next-method-p
  1592.                          (let ((cont (gensym)) ; Variable für die Continuation
  1593.                                (req-dummies ; Liste von reqanz Dummies
  1594.                                  (n-gensyms reqanz)
  1595.                                )
  1596.                                (rest-dummy (if (or restp (> optanz 0)) (gensym)))
  1597.                                (lambda-expr `(LAMBDA ,@lambdabody-part1 ,@lambdabody-part2)))
  1598.                            `(; neue Lambda-Liste:
  1599.                              (,cont
  1600.                               ,@req-dummies
  1601.                               ,@(if rest-dummy `(&REST ,rest-dummy) '())
  1602.                              )
  1603.                              (MACROLET
  1604.                                ((CALL-NEXT-METHOD ()
  1605.                                   ,(if rest-dummy
  1606.                                      `(LIST 'IF ',cont
  1607.                                         (LIST 'APPLY ',cont
  1608.                                           ,@(mapcar #'(lambda (x) `',x) req-dummies)
  1609.                                           ',rest-dummy
  1610.                                         )
  1611.                                         (LIST 'APPLY '(FUNCTION %NO-NEXT-METHOD)
  1612.                                           ',self
  1613.                                           ,@(mapcar #'(lambda (x) `',x) req-dummies)
  1614.                                           ',rest-dummy
  1615.                                       ) )
  1616.                                      `(LIST 'IF ',cont
  1617.                                         (LIST 'FUNCALL ',cont
  1618.                                           ,@(mapcar #'(lambda (x) `',x) req-dummies)
  1619.                                         )
  1620.                                         (LIST '%NO-NEXT-METHOD
  1621.                                           ',self
  1622.                                           ,@(mapcar #'(lambda (x) `',x) req-dummies)
  1623.                                       ) )
  1624.                                    )
  1625.                                 )
  1626.                                 (NEXT-METHOD-P () ',cont)
  1627.                                )
  1628.                                ; neuer Body:
  1629.                                ,(if rest-dummy
  1630.                                   `(APPLY (FUNCTION ,lambda-expr)
  1631.                                           ,@req-dummies ,rest-dummy
  1632.                                    )
  1633.                                   `(,lambda-expr ,@req-dummies)
  1634.                                 )
  1635.                             ))
  1636.                          )
  1637.                          `(,@lambdabody-part1
  1638.                            (MACROLET
  1639.                              ((CALL-NEXT-METHOD ()
  1640.                                 (ERROR #+DEUTSCH "~S ~S: ~S ist in ~S-Methoden nicht erlaubt."
  1641.                                        #+ENGLISH "~S ~S: ~S is invalid within ~S methods"
  1642.                                        ',caller ',funname 'CALL-NEXT-METHOD ',(first qualifiers)
  1643.                               ) )
  1644.                               (NEXT-METHOD-P ()
  1645.                                 (ERROR #+DEUTSCH "~S ~S: ~S ist in ~S-Methoden nicht erlaubt."
  1646.                                        #+ENGLISH "~S ~S: ~S is invalid within ~S methods"
  1647.                                        ',caller ',funname 'NEXT-METHOD-P ',(first qualifiers)
  1648.                              )) )
  1649.                              ,@lambdabody-part2
  1650.                           ))
  1651.                 )) ) ) )
  1652.             `(MAKE-STANDARD-METHOD
  1653.                :INITFUNCTION
  1654.                  #'(LAMBDA (,self)
  1655.                      ,@(if compile '((DECLARE (COMPILE))))
  1656.                      (%OPTIMIZE-FUNCTION-LAMBDA
  1657.                        ,(if wants-next-method-p `(T) `())
  1658.                        ,@lambdabody
  1659.                    ) )
  1660.                :WANTS-NEXT-METHOD-P ',wants-next-method-p
  1661.                :PARAMETER-SPECIALIZERS (LIST ,@(nreverse req-specializer-forms))
  1662.                :QUALIFIERS ',qualifiers
  1663.                :SIGNATURE '(,reqanz ,optanz ,restp ,keyp ,keywords ,allowp)
  1664.              )
  1665. ) ) ) ) ) )
  1666.  
  1667. ;; 28.1.6.3. agreement on parameter specializers and qualifiers
  1668. (defun methods-agree-p (method1 method2)
  1669.   (and (equal (std-method-qualifiers method1) (std-method-qualifiers method2))
  1670.        (specializers-agree-p (std-method-parameter-specializers method1)
  1671.                              (std-method-parameter-specializers method2)
  1672. ) )    )
  1673. (defun specializers-agree-p (specializers1 specializers2)
  1674.   (and (eql (length specializers1) (length specializers2))
  1675.        (every #'(lambda (parspec1 parspec2)
  1676.                   (or ; zwei gleiche Klassen?
  1677.                       (eq parspec1 parspec2)
  1678.                       ; zwei gleiche EQL-Specializer?
  1679.                       (and (consp parspec1) (consp parspec2)
  1680.                            (eql (second parspec1) (second parspec2))
  1681.                 ) )   )
  1682.               specializers1 specializers2
  1683. ) )    )
  1684.  
  1685. ;; 28.1.6.2. applicable methods
  1686. (defun method-applicable-p (method required-arguments)
  1687.   (every #'typep required-arguments (std-method-parameter-specializers method))
  1688. )
  1689.  
  1690. ;; 28.1.7.1. sorting the applicable methods by precedence order
  1691. (defun sort-applicable-methods (methods required-arguments argument-order)
  1692.   (sort (copy-list methods)
  1693.         #'(lambda (method1 method2) ; method1 < method2 ?
  1694.             (let ((specializers1 (std-method-parameter-specializers method1))
  1695.                   (specializers2 (std-method-parameter-specializers method2)))
  1696.               (dolist (arg-index argument-order nil)
  1697.                 (let ((arg (nth arg-index required-arguments))
  1698.                       (psp1 (nth arg-index specializers1))
  1699.                       (psp2 (nth arg-index specializers2)))
  1700.                   (if (consp psp1)
  1701.                     (if (consp psp2)
  1702.                       nil        ; (EQL x) = (EQL x)
  1703.                       (return t) ; (EQL x) < <class>  ==>  method1 < method2
  1704.                     )
  1705.                     (if (consp psp2)
  1706.                       (return nil) ; <class> > (EQL x)   ==>  method1 > method2
  1707.                       ; Zwei Klassen: vergleiche die Position in der CPL von arg:
  1708.                       (let* ((cpl (class-precedence-list (class-of arg)))
  1709.                              (pos1 (position psp1 cpl))
  1710.                              (pos2 (position psp2 cpl)))
  1711.                         (cond ((< pos1 pos2) (return t)) ; method1 < method2
  1712.                               ((> pos1 pos2) (return nil)) ; method1 > method2
  1713.                       ) )
  1714.           ) ) ) ) ) )
  1715. ) )
  1716.  
  1717. ; Für STANDARD Methodenkombination: Aufspalten der Methoden nach Qualifiern
  1718. (defun partition-method-list (methods)
  1719.   (let ((primary-methods '())
  1720.         (before-methods '())
  1721.         (after-methods '())
  1722.         (around-methods '()))
  1723.     (dolist (method methods)
  1724.       (let ((quals (std-method-qualifiers method)))
  1725.         (cond ((equal quals '())        (push method primary-methods))
  1726.               ((equal quals '(:before)) (push method before-methods))
  1727.               ((equal quals '(:after))  (push method after-methods))
  1728.               ((equal quals '(:around)) (push method around-methods))
  1729.     ) ) )
  1730.     (values
  1731.       (nreverse primary-methods)
  1732.       (nreverse before-methods)
  1733.       (nreverse after-methods)
  1734.       (nreverse around-methods)
  1735. ) ) )
  1736.  
  1737.  
  1738. ;;; Generische Funktionen
  1739.  
  1740. ; Low-Level-Repräsentation:
  1741. ; Compilierte Funktionen (Cclosures), bei denen im Flag-Byte des Code-Vektors
  1742. ; ein bestimmtes Bit gesetzt ist. Hintendran zusätzlich:
  1743. ; - die Signatur, eine Liste (reqanz optanz restp keywords allowp),
  1744. ; - die Argument-Precedence-Order, als Liste der Zahlen von 0 bis reqanz-1,
  1745. ; - die Liste aller Methoden.
  1746.  
  1747. ; Der Compiler benutzt (bei GENERIC-FLET, GENERIC-LABELS) und der Evaluator
  1748. ; setzt ebenfalls voraus, daß eine generische Funktion ihre Aufrufkonvention
  1749. ; nicht ändert.
  1750. ; Eine generische Funktion mit Signatur (reqanz optanz restp keywords allowp)
  1751. ; ist von Anfang an (!) eine compilierte Funktion mit
  1752. ;         reqanz  required-Parametern
  1753. ;         0       optionalen Parametern
  1754. ;         &rest genau dann wenn (or (> optanz 0) restp),
  1755. ;         ohne &key.
  1756. (defun callinfo (reqanz optanz restp keywords allowp)
  1757.   (declare (ignore keywords allowp))
  1758.   (list reqanz 0 (or (> optanz 0) restp) nil nil nil)
  1759. )
  1760.  
  1761. (defun gf-signature (gf)
  1762.   (sys::%record-ref gf 3)
  1763. )
  1764. (defun (setf gf-signature) (new gf)
  1765.   (setf (sys::%record-ref gf 3) new)
  1766. )
  1767.  
  1768. (defun gf-argorder (gf)
  1769.   (sys::%record-ref gf 4)
  1770. )
  1771. (defun (setf gf-argorder) (new gf)
  1772.   (setf (sys::%record-ref gf 4) new)
  1773. )
  1774.  
  1775. (defun gf-methods (gf)
  1776.   (sys::%record-ref gf 5)
  1777. )
  1778. (defun (setf gf-methods) (new gf)
  1779.   (setf (sys::%record-ref gf 5) new)
  1780. )
  1781.  
  1782. ; Der Dispatch-Code für generische Funktionen wird mit
  1783. ; `(%GENERIC-FUNCTION-LAMBDA ,@lambdabody)
  1784. ; - ähnlich zu `(FUNCTION (LAMBDA ,@lambdabody)) - gebildet.
  1785. ; Es dürfen darin nicht vorkommen:
  1786. ; - Zugriff auf dynamische Variablen, Binden von dynamischen Variablen,
  1787. ; - nichttriviale BLOCK, RETURN-FROM, TAGBODY, GO Konstrukte,
  1788. ; - Aufruf globaler Funktionen, die nicht inline sind,
  1789. ; - Bildung von nicht-autonomen Funktionen (Closures).
  1790. ; Nötig ist also:
  1791. ;   (declare (inline case eql eq typep
  1792. ;                    arrayp bit-vector-p characterp complexp consp floatp
  1793. ;                    functionp clos::generic-function-p hash-table-p integerp
  1794. ;                    listp null numberp packagep pathnamep random-state-p
  1795. ;                    rationalp readtablep realp sys::sequencep
  1796. ;                    clos::std-instance-p streamp stringp symbolp vectorp
  1797. ;                    class-of cons gethash funcall apply ...
  1798. ;   )        )
  1799. ; Das Ergebnis ist nicht(!) als eigenständige Funktion aufrufbar, sondern
  1800. ; bedarf der Nachbearbeitung: Die Konstanten C_0 ... C_(k-1) C_k müssen zu
  1801. ; #(C_0 ... C_(k-1) . [Rest von C_k]) zusammengefaßt werden, k = 0 oder 1.
  1802.  
  1803. ; Liefert eine generische Funktion ohne Dispatch-Code. Nicht aufrufbar!!
  1804. (let* ((prototype ; eine sinnlose Funktion
  1805.          #'(lambda (&rest args) (declare (compile) (ignore args))
  1806.              (tagbody 1 (go 1))
  1807.            )
  1808.        )
  1809.        (prototype-code (sys::%record-ref prototype 1)))
  1810.   (defun %make-gf (name signature argorder methods)
  1811.     (sys::%make-closure name prototype-code
  1812.                         (list nil signature argorder methods)
  1813.   ) )
  1814. )
  1815.  
  1816. #|
  1817. ; Besser in compiler.lsp??
  1818. (defun make-gf (name lambdabody signature argorder methods)
  1819.   (let ((preliminary
  1820.           (eval `(LET ()
  1821.                    (DECLARE (COMPILE))
  1822.                    (%GENERIC-FUNCTION-LAMBDA ,@lambdabody)
  1823.                  )
  1824.        )) )
  1825.     (sys::%make-closure
  1826.       name
  1827.       (sys::closure-codevec preliminary)
  1828.       (list
  1829.         (case (sys::%record-length preliminary)
  1830.           (3 (sys::%record-ref preliminary 2))
  1831.           (4 (let ((consts (sys::%record-ref preliminary 3)))
  1832.                (setf (svref consts 0) (sys::%record-ref preliminary 2))
  1833.                consts
  1834.         ) )  )
  1835.         signature
  1836.         argorder
  1837.         methods
  1838. ) ) ) )
  1839. |#
  1840.  
  1841.  
  1842. #|
  1843.  
  1844. ;; Generische Funktionen mit primitivem Dispatch:
  1845.  
  1846. (defun make-slow-gf (name signature argorder methods)
  1847.   (let* ((final (%make-gf name signature argorder methods))
  1848.          (preliminary
  1849.            (eval `(LET ((GF ',final))
  1850.                     (DECLARE (COMPILE))
  1851.                     (%GENERIC-FUNCTION-LAMBDA (&REST ARGS)
  1852.                       (DECLARE (INLINE APPLY))
  1853.                       (APPLY 'SLOW-FUNCALL-GF GF ARGS)
  1854.                   ) )
  1855.         )) )
  1856.     (setf (sys::%record-ref final 1) (sys::closure-codevec preliminary))
  1857.     (setf (sys::%record-ref final 2)
  1858.           (case (sys::%record-length preliminary)
  1859.             (3 (sys::%record-ref preliminary 2))
  1860.             (4 (let ((consts (sys::%record-ref preliminary 3)))
  1861.                  (setf (svref consts 0) (sys::%record-ref preliminary 2))
  1862.                  consts
  1863.           ) )  )
  1864.     )
  1865.     final
  1866. ) )
  1867.  
  1868. (let* ((prototype
  1869.          (let ((gf 'magic))
  1870.            (declare (compile))
  1871.            (%generic-function-lambda (&rest args)
  1872.              (declare (inline apply))
  1873.              (apply 'slow-funcall-gf gf args)
  1874.        ) ) )
  1875.        (prototype-code (sys::%record-ref prototype 1))
  1876.        (prototype-consts (sys::%record-ref prototype 3)))
  1877.   (defun finalize-slow-gf (gf)
  1878.     (setf (sys::%record-ref gf 1) prototype-code)
  1879.     (setf (sys::%record-ref gf 2) (substitute gf 'magic prototype-consts))
  1880.   )
  1881.   (defun warn-if-gf-already-called (gf) )
  1882. )
  1883.  
  1884. ; Aufruf einer generischen Funktion
  1885. (defun slow-funcall-gf (gf &rest args)
  1886.   (let ((reqanz (first (gf-signature gf)))
  1887.         (arg-order (gf-argorder gf))
  1888.         (methods (gf-methods gf)))
  1889.     (unless (>= (length args) reqanz)
  1890.       (error #+DEUTSCH "Zu wenig Argumente für ~S: ~S"
  1891.              #+ENGLISH "Too few arguments to ~S: ~S"
  1892.              gf args
  1893.     ) )
  1894.     (let ((req-args (subseq args 0 reqanz)))
  1895.       ; Determine the effective method:
  1896.       ; 1. Select the applicable methods:
  1897.       (setq methods
  1898.         (remove-if-not #'(lambda (method) (method-applicable-p method req-args))
  1899.                        methods
  1900.       ) )
  1901.       (when (null methods)
  1902.         (return-from slow-funcall-gf (apply #'no-applicable-method gf args))
  1903.       )
  1904.       ; 2. Sort the applicable methods by precedence order:
  1905.       (setq methods (sort-applicable-methods methods req-args arg-order))
  1906.       ; 3. Apply method combination:
  1907.       ; Nur STANDARD Methoden-Kombination ist implementiert.
  1908.       ; Aufspalten in einzelne Methoden-Typen:
  1909.       (multiple-value-bind (primary-methods before-methods after-methods around-methods)
  1910.           (partition-method-list methods)
  1911.         (when (null primary-methods)
  1912.           (return-from slow-funcall-gf (apply #'no-primary-method gf args))
  1913.         )
  1914.         ; Methoden zu einer "effektiven Methode" kombinieren:
  1915.         (labels ((ef-1 (primary-methods before-methods after-methods around-methods)
  1916.                    (if (null around-methods)
  1917.                      (ef-2 primary-methods before-methods after-methods)
  1918.                      (let* ((1method (first around-methods))
  1919.                             (1function (std-method-function 1method)))
  1920.                        (if (std-method-wants-next-method-p 1method)
  1921.                          (let ((next-ef
  1922.                                  (ef-1 primary-methods before-methods after-methods (rest around-methods))
  1923.                               ))
  1924.                            #'(lambda (&rest args) (apply 1function next-ef args))
  1925.                          )
  1926.                          #'(lambda (&rest args) (apply 1function args))
  1927.                  ) ) ) )
  1928.                  (ef-2 (primary-methods before-methods after-methods)
  1929.                    (if (null after-methods)
  1930.                      (ef-3 primary-methods before-methods)
  1931.                      (let* ((1method (first after-methods))
  1932.                             (1function (std-method-function 1method)))
  1933.                        (let ((next-ef (ef-2 primary-methods before-methods (rest after-methods))))
  1934.                          #'(lambda (&rest args) (multiple-value-prog1 (apply next-ef args) (apply 1function args)))
  1935.                  ) ) ) )
  1936.                  (ef-3 (primary-methods before-methods)
  1937.                    (if (null before-methods)
  1938.                      (ef-4 primary-methods)
  1939.                      (let* ((1method (first before-methods))
  1940.                             (1function (std-method-function 1method)))
  1941.                        (let ((next-ef (ef-3 primary-methods (rest before-methods))))
  1942.                          #'(lambda (&rest args) (progn (apply 1function args) (apply next-ef args)))
  1943.                  ) ) ) )
  1944.                  (ef-4 (primary-methods)
  1945.                    (if (null primary-methods)
  1946.                      nil ; keine Funktion, NEXT-METHOD-P reagiert darauf
  1947.                      (let* ((1method (first primary-methods))
  1948.                             (1function (std-method-function 1method)))
  1949.                        (if (std-method-wants-next-method-p 1method)
  1950.                          (let ((next-ef (ef-4 (rest primary-methods))))
  1951.                            #'(lambda (&rest args) (apply 1function next-ef args))
  1952.                          )
  1953.                          #'(lambda (&rest args) (apply 1function args))
  1954.                 )) ) ) )
  1955.           (let ((ef (ef-1 primary-methods before-methods after-methods around-methods)))
  1956.             ; Keyword-Check (28.1.6.4., 28.1.6.5.) ??
  1957.             ; Effektive Methode aufrufen:
  1958.             (funcall ef args)
  1959. ) ) ) ) ) )
  1960.  
  1961. |#
  1962.  
  1963.  
  1964. ;; Generische Funktionen mit optimiertem Dispatch:
  1965.  
  1966. (defun make-fast-gf (name signature argorder)
  1967.   (let ((gf (%make-gf name signature argorder '())))
  1968.     (finalize-fast-gf gf)
  1969.     gf
  1970. ) )
  1971.  
  1972. (let ((prototype-table (make-hash-table :test #'equal)))
  1973.   (defun finalize-fast-gf (gf)
  1974.     (let* ((signature (gf-signature gf))
  1975.            (reqanz (first signature))
  1976.            (restp (or (third signature) (> (second signature) 0)))
  1977.            (hash-key (cons reqanz restp))
  1978.            (prototype
  1979.              (or (gethash hash-key prototype-table)
  1980.                  (setf (gethash hash-key prototype-table)
  1981.                        (let* ((reqvars (n-gensyms reqanz))
  1982.                               (proto-gf
  1983.                                 (eval `(LET ((GF 'MAGIC))
  1984.                                          (DECLARE (COMPILE))
  1985.                                          (%GENERIC-FUNCTION-LAMBDA (,@reqvars ,@(if restp '(&REST ARGS) '()))
  1986.                                            (DECLARE (INLINE APPLY))
  1987.                                            (APPLY 'INITIAL-FUNCALL-GF GF ,@reqvars ,(if restp `ARGS `'NIL))
  1988.                                        ) )
  1989.                              )) )
  1990.                          ; (sys::%record-ref proto-gf 1) müssen wir aufbewahren.
  1991.                          ; (sys::%record-ref proto-gf 3) = #(NIL INITIAL-FUNCALL-GF MAGIC)
  1992.                          (sys::%record-ref proto-gf 1)
  1993.           )) )   )     )
  1994.       (setf (sys::%record-ref gf 1) prototype)
  1995.       (setf (sys::%record-ref gf 2) (vector 'NIL 'INITIAL-FUNCALL-GF gf))
  1996.   ) )
  1997.   (defun warn-if-gf-already-called (gf)
  1998.     (let* ((signature (gf-signature gf))
  1999.            (reqanz (first signature))
  2000.            (restp (or (third signature) (> (second signature) 0)))
  2001.            (hash-key (cons reqanz restp))
  2002.            (prototype (gethash hash-key prototype-table)))
  2003.       (unless (eq (sys::%record-ref gf 1) prototype)
  2004.         (warn #+DEUTSCH "Die generische Funktion ~S wird modifiziert, wurde aber bereits aufgerufen."
  2005.               #+ENGLISH "The generic function ~S is being modified, but has already been called."
  2006.               gf
  2007.   ) ) ) )
  2008. )
  2009.  
  2010. ; Der eigentliche Dispatch-Code wird erst beim ersten Aufruf der funktion
  2011. ; berechnet, um aufeinanderfolgende Methoden-Definitionen nicht zu teuer
  2012. ; zu machen.
  2013.  
  2014. ; Erster Aufruf einer generischen Funktion:
  2015. (defun initial-funcall-gf (gf &rest args)
  2016.   (install-dispatch gf)
  2017.   (apply gf args)
  2018. )
  2019.  
  2020. ; Installiert den endgültigen Dispatch-Code in eine generische Funktion.
  2021. (defun install-dispatch (gf)
  2022.   (multiple-value-bind (bindings lambdabody) (compute-dispatch gf)
  2023.     (let ((preliminary
  2024.             (eval `(LET ,bindings
  2025.                      (DECLARE (COMPILE))
  2026.                      (%GENERIC-FUNCTION-LAMBDA ,@lambdabody)
  2027.                    )
  2028.          )) )
  2029.       (setf (sys::%record-ref gf 1) (sys::%record-ref preliminary 1))
  2030.       (setf (sys::%record-ref gf 2)
  2031.             (let ((consts (sys::%record-ref preliminary 3)))
  2032.                (setf (svref consts 0) (sys::%record-ref preliminary 2))
  2033.                consts
  2034.       )     )
  2035. ) ) )
  2036.  
  2037. ; Berechnet den Dispatch-Code einer generischen Funktion.
  2038. ; Er hat folgendes Aussehen:
  2039. ; (LAMBDA (variablen)      ; die required einzeln, alles andere mit &rest
  2040. ;   (DECLARE (INLINE ...)) ; alles inline wegen %GENERIC-FUNCTION-LAMBDA
  2041. ;   If-Kaskaden, dabei werden EQL-Parameter-Specializer und die meisten
  2042. ;   Builtin-Klassen per TYPEP inline abgefragt.
  2043. ;   Für die anderen required-Parameter wird CLASS-OF aufgerufen, die Ergebnisse
  2044. ;   gesammelt und als Index in eine Hash-Tabelle genommen. Dort steht die
  2045. ;   effektive Methode:
  2046. ;   (LET ((EM (GETHASH (CONS (CLASS-OF ...) ...) ht1)))
  2047. ;     (WHEN EM (RETURN-FROM block (APPLY EM Argumente)))
  2048. ;   )
  2049. ;   Wenn das nicht gelungen ist:
  2050. ;   (APPLY 'COMPUTE-AND-ADD-EFFECTIVE-METHOD gf Argumente)
  2051. ; )
  2052. (defun compute-dispatch (gf)
  2053.   (let* ((signature (gf-signature gf))
  2054.          (req-anz (first signature))
  2055.          (req-vars (n-gensyms req-anz))
  2056.          (restp (or (third signature) (> (second signature) 0)))
  2057.          (rest-var (if restp (gensym)))
  2058.          (apply-fun (if restp 'APPLY 'FUNCALL))
  2059.          (apply-args `(,@req-vars ,@(if restp `(,rest-var) '())))
  2060.          (arg-order (gf-argorder gf))
  2061.          (methods (gf-methods gf))
  2062.          (block-name (gensym))
  2063.          (maybe-no-applicable nil)
  2064.          (ht-vars '())) ; Liste von Hashtabellen-Variablen und ihren Inits
  2065.     ; Wir machen eine Rekursion über die Argumente.
  2066.     (labels
  2067.        ((recursion (remaining-args ; ein nthcdr von arg-order
  2068.                     remaining-methods ; Teilliste von methods
  2069.                     class-of-exprs ; Liste von CLASS-OF Expressions
  2070.                    )
  2071.           (if (null remaining-methods)
  2072.             (progn
  2073.               (setq maybe-no-applicable t)
  2074.               'NIL ; nichts tun, später NO-APPLICABLE-METHOD aufrufen
  2075.             )
  2076.             (if (null remaining-args)
  2077.               ; alle Argumente abgearbeitet
  2078.               (let ((ht-var (gensym))
  2079.                     (n (length class-of-exprs)) ; indiziere mit n-Tupeln
  2080.                     ht-init ; Expression zum Initialisieren von ht-var
  2081.                     ht-key-binding ; Bindung einer Variablen an ein n-Tupel
  2082.                     em-expr ; Expression zum Auffinden der EM
  2083.                     setf-em-expr ; Expression-Teil zum Setzen der EM
  2084.                    )
  2085.                 (if (eql n 0)
  2086.                   (setq ht-init 'NIL
  2087.                         ht-key-binding '()
  2088.                         em-expr ht-var
  2089.                         setf-em-expr `(SETQ ,ht-var)
  2090.                   )
  2091.                   (let ((tuple-var (gensym)))
  2092.                     (setq ht-init
  2093.                           `(MAKE-HASH-TABLE
  2094.                              :TEST (FUNCTION ,(if (eql n 1) 'EQ 'EQUAL))
  2095.                            )
  2096.                           ht-key-binding
  2097.                           `((,tuple-var
  2098.                              ,(let ((tuple-fun (hash-tuple-function n)))
  2099.                                 (if (member '&rest (second tuple-fun))
  2100.                                   `(,tuple-fun ,@(reverse class-of-exprs))
  2101.                                   ; kein &rest -> kann optimieren
  2102.                                   ; (der Compiler kann's noch nicht so gut)
  2103.                                   (sublis (mapcar #'cons (second tuple-fun) (reverse class-of-exprs))
  2104.                                           (third tuple-fun)
  2105.                               ) ) )
  2106.                            ))
  2107.                           em-expr
  2108.                           `(GETHASH ,tuple-var ,ht-var)
  2109.                           setf-em-expr
  2110.                           ; `(SETF (GETHASH ,tuple-var ,ht-var)) ginge auch;
  2111.                           ; das Folgende spart aber zwei temporäre Variablen:
  2112.                           `(SYSTEM::PUTHASH ,tuple-var ,ht-var)
  2113.                 ) ) )
  2114.                 (push (list ht-var ht-init) ht-vars)
  2115.                 `(LET ,ht-key-binding
  2116.                    (RETURN-FROM ,block-name
  2117.                      (,apply-fun
  2118.                       (OR ,em-expr
  2119.                           (,@setf-em-expr
  2120.                                 (,apply-fun 'COMPUTE-EFFECTIVE-METHOD ',gf
  2121.                                             ,@apply-args
  2122.                       )   )     )
  2123.                       ,@apply-args
  2124.                  ) ) )
  2125.               )
  2126.               ; nächstes Argument abarbeiten:
  2127.               (let* ((arg-index (first remaining-args))
  2128.                      (arg-var (nth arg-index req-vars))
  2129.                      (eql-cases ; alle EQL-Specializer für dieses Argument
  2130.                        (remove-duplicates
  2131.                          (mapcar #'second
  2132.                            (remove-if-not #'consp
  2133.                              (mapcar #'(lambda (m)
  2134.                                          (nth arg-index
  2135.                                            (std-method-parameter-specializers m)
  2136.                                        ) )
  2137.                                remaining-methods
  2138.                          ) ) )
  2139.                          :test #'eql
  2140.                      ) )
  2141.                      (eql-caselist ; Fall-Liste für CASE
  2142.                        (mapcar
  2143.                          #'(lambda (object)
  2144.                              `((,object)
  2145.                                ,(recursion
  2146.                                   (cdr remaining-args)
  2147.                                   (remove-if-not
  2148.                                     #'(lambda (m)
  2149.                                         (typep object
  2150.                                           (nth arg-index
  2151.                                             (std-method-parameter-specializers m)
  2152.                                       ) ) )
  2153.                                     remaining-methods
  2154.                                   )
  2155.                                   class-of-exprs
  2156.                                 )
  2157.                               )
  2158.                            )
  2159.                          eql-cases
  2160.                     )) )
  2161.                 ; Fürs weitere brauchen wir die EQL-Methoden nicht mehr zu
  2162.                 ; betrachten.
  2163.                 (setq remaining-methods
  2164.                       (remove-if
  2165.                         #'(lambda (m)
  2166.                             (consp
  2167.                               (nth arg-index
  2168.                                 (std-method-parameter-specializers m)
  2169.                           ) ) )
  2170.                         remaining-methods
  2171.                 )     )
  2172.                 ((lambda (other-cases)
  2173.                    (if eql-caselist
  2174.                      `(CASE ,arg-var ,@eql-caselist (T ,other-cases))
  2175.                      other-cases
  2176.                  ) )
  2177.                  (let ((classes
  2178.                          (delete <t>
  2179.                            (delete-duplicates
  2180.                              (mapcar #'(lambda (m)
  2181.                                          (nth arg-index
  2182.                                            (std-method-parameter-specializers m)
  2183.                                        ) )
  2184.                                      remaining-methods
  2185.                       )) ) ) )
  2186.                    ; Falls alle Klassen, auf die zu testen ist,
  2187.                    ; Built-In-Klassen sind, machen wir den Typ-Dispatch
  2188.                    ; inline. Denn in der Hierarchie der Built-In-Klassen
  2189.                    ; (die außer NULL und VECTOR keine mehrfache Vererbung
  2190.                    ; kennt) sind alle CPLs konsistent. Man kann daher mit
  2191.                    ; (subclassp (class-of obj) class) == (typep obj class)
  2192.                    ; arbeiten.
  2193.                    ; Im anderen Fall ist sowieso ein Hash-Tabellen-Zugriff
  2194.                    ; nötig, dann sparen wir uns den Test auf die Built-In-
  2195.                    ; Klassen und beziehen ihn in die Hash-Tabelle ein.
  2196.                    (if (and (every #'bc-p classes)
  2197.                             (<= (length classes) 5) ; zu viele Fälle -> hashen
  2198.                        )
  2199.                      (labels
  2200.                         ((built-in-subtree (class remaining-classes remaining-methods)
  2201.                            ; behandelt die Fälle, daß das Argument der Klasse
  2202.                            ; class angehört und auf Zugehörigkeit zu einer der
  2203.                            ; remaining-classes abgeprüft werden muß.
  2204.                            ; (Man kann voraussetzen, daß (bc-and class x) /= nil
  2205.                            ; für alle x aus remaining-classes.)
  2206.                            (if (null remaining-classes)
  2207.                              ; Keine Fallunterscheidung mehr nötig
  2208.                              (recursion
  2209.                                (cdr remaining-args)
  2210.                                (remove-if-not
  2211.                                  #'(lambda (m)
  2212.                                      (bc-and class
  2213.                                        (nth arg-index
  2214.                                          (std-method-parameter-specializers m)
  2215.                                    ) ) )
  2216.                                  remaining-methods
  2217.                                )
  2218.                                class-of-exprs
  2219.                              )
  2220.                              ; Fallunterscheidung mittels TYPEP
  2221.                              (let ((test-class (first remaining-classes)))
  2222.                                ; besser test-class maximal wählen:
  2223.                                (loop
  2224.                                  (let ((other-class
  2225.                                          (find-if
  2226.                                            #'(lambda (x)
  2227.                                                (and (subclassp test-class x)
  2228.                                                     (not (eq test-class x))
  2229.                                              ) )
  2230.                                            remaining-classes
  2231.                                       )) )
  2232.                                    (unless other-class (return))
  2233.                                    (setq test-class other-class)
  2234.                                ) )
  2235.                                `(IF (TYPEP ,arg-var ',(class-classname test-class))
  2236.                                   ,(built-in-subtree
  2237.                                      (bc-and class test-class) ; /= nil !
  2238.                                      (remove 'nil
  2239.                                        (mapcar
  2240.                                          #'(lambda (x) (bc-and x test-class))
  2241.                                          (remove test-class remaining-classes)
  2242.                                      ) )
  2243.                                      (remove-if-not
  2244.                                        #'(lambda (m)
  2245.                                            (bc-and
  2246.                                              (nth arg-index
  2247.                                                (std-method-parameter-specializers m)
  2248.                                              )
  2249.                                              test-class
  2250.                                          ) )
  2251.                                        remaining-methods
  2252.                                    ) )
  2253.                                   ,(built-in-subtree
  2254.                                      (bc-and-not class test-class) ; /= nil !
  2255.                                      (remove 'nil
  2256.                                        (mapcar
  2257.                                          #'(lambda (x) (bc-and-not x test-class))
  2258.                                          remaining-classes
  2259.                                      ) )
  2260.                                      (remove-if-not
  2261.                                        #'(lambda (m)
  2262.                                            (bc-and-not
  2263.                                              (nth arg-index
  2264.                                                (std-method-parameter-specializers m)
  2265.                                              )
  2266.                                              test-class
  2267.                                          ) )
  2268.                                        remaining-methods
  2269.                                    ) )
  2270.                                 )
  2271.                         )) ) )
  2272.                        (built-in-subtree <t> classes remaining-methods)
  2273.                      )
  2274.                      (recursion
  2275.                        (cdr remaining-args)
  2276.                        remaining-methods
  2277.                        (cons `(CLASS-OF ,arg-var) class-of-exprs)
  2278.                 )) ) )
  2279.        )) ) ) )
  2280.       (let ((form (recursion arg-order methods '())))
  2281.         (values
  2282.           ; bindings
  2283.           (nreverse ht-vars)
  2284.           ; lambdabody
  2285.           `((,@req-vars ,@(if restp `(&REST ,rest-var) '()))
  2286.             (DECLARE
  2287.               (INLINE ; für die Fallunterscheidungen:
  2288.                       CASE EQL EQ TYPEP
  2289.                       ; bei der Inline-Expansion von TYPEP auf Built-In-Klassen:
  2290.                       ARRAYP BIT-VECTOR-P CHARACTERP COMPLEXP CONSP FLOATP
  2291.                       FUNCTIONP CLOS::GENERIC-FUNCTION-P HASH-TABLE-P INTEGERP
  2292.                       LISTP NULL NUMBERP PACKAGEP PATHNAMEP RANDOM-STATE-P
  2293.                       RATIONALP READTABLEP REALP SYS::SEQUENCEP
  2294.                       CLOS::STD-INSTANCE-P STREAMP STRINGP SYMBOLP VECTORP
  2295.                       ; Finden und Aufruf der effektiven Methode:
  2296.                       CLASS-OF CONS GETHASH SYS::PUTHASH FUNCALL APPLY
  2297.             ) )
  2298.             (BLOCK ,block-name
  2299.               ,form
  2300.               ,@(if maybe-no-applicable
  2301.                   `((,apply-fun 'NO-APPLICABLE-METHOD ',gf ,@apply-args))
  2302.                 )
  2303.            ))
  2304. ) ) ) ) )
  2305.  
  2306. ; Unsere EQUAL-Hashfunktion schaut in Cons-Bäume nur bis Tiefe 4 hinein.
  2307. ; Ein Tupel aus maximal 16 Elementen kann zu einem solchen Baum gemacht werden.
  2308. (defun hash-tuple-function (n) ; n>0
  2309.   (case n
  2310.     (1 '(lambda (t1) t1))
  2311.     (2 '(lambda (t1 t2) (cons t1 t2)))
  2312.     (3 '(lambda (t1 t2 t3) (cons t1 (cons t2 t3))))
  2313.     (4 '(lambda (t1 t2 t3 t4) (cons (cons t1 t2) (cons t3 t4))))
  2314.     (5 '(lambda (t1 t2 t3 t4 t5) (cons (cons t1 t2) (cons t3 (cons t4 t5)))))
  2315.     (6 '(lambda (t1 t2 t3 t4 t5 t6)
  2316.           (cons (cons t1 t2) (cons (cons t3 t4) (cons t5 t6))) ))
  2317.     (7 '(lambda (t1 t2 t3 t4 t5 t6 t7)
  2318.           (cons (cons t1 (cons t2 t3)) (cons (cons t4 t5) (cons t6 t7))) ))
  2319.     (8 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8)
  2320.           (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons t7 t8))) ))
  2321.     (9 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9)
  2322.           (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons t7 (cons t8 t9)))) ))
  2323.     (10 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10)
  2324.            (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons (cons t7 t8) (cons t9 t10)))) ))
  2325.     (11 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11)
  2326.            (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 (cons t6 t7)) (cons (cons t8 t9) (cons t10 t11)))) ))
  2327.     (12 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12)
  2328.            (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons (cons t5 t6) (cons t7 t8)) (cons (cons t9 t10) (cons t11 t12)))) ))
  2329.     (13 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13)
  2330.            (cons (cons (cons t1 t2) (cons t3 (cons t4 t5))) (cons (cons (cons t6 t7) (cons t8 t9)) (cons (cons t10 t11) (cons t12 t13)))) ))
  2331.     (14 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14)
  2332.            (cons (cons (cons t1 t2) (cons (cons t3 t4) (cons t5 t6))) (cons (cons (cons t7 t8) (cons t9 t10)) (cons (cons t11 t12) (cons t13 t14)))) ))
  2333.     (15 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15)
  2334.            (cons (cons (cons t1 (cons t2 t3)) (cons (cons t4 t5) (cons t6 t7))) (cons (cons (cons t8 t9) (cons t10 t11)) (cons (cons t12 t13) (cons t14 t15)))) ))
  2335.     (16 '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16)
  2336.            (cons (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons t7 t8))) (cons (cons (cons t9 t10) (cons t11 t12)) (cons (cons t13 t14) (cons t15 t16)))) ))
  2337.     (t '(lambda (t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 &rest more-t)
  2338.           (cons (cons (cons (cons t1 t2) (cons t3 t4)) (cons (cons t5 t6) (cons t7 t8))) (cons (cons (cons t9 t10) (cons t11 t12)) (cons (cons t13 t14) more-t))) ))
  2339. ) )
  2340.  
  2341. ; Berechnet die effektive Methode zu gegebenen Argumenten.
  2342. ; Es ist eigentlich die effektive Methode zu allen Argumenten, die dieselben
  2343. ; EQL- und Klassen-Einschränkungen haben wie die gegebenen Argumente, aber
  2344. ; darum hat sich compute-dispatch schon gekümmert.
  2345. (defun compute-effective-method (gf &rest args)
  2346.   (let* ((signature (gf-signature gf))
  2347.          (req-anz (first signature))
  2348.          (req-vars (n-gensyms req-anz))
  2349.          (req-args (subseq args 0 req-anz))
  2350.          (restp (or (third signature) (> (second signature) 0)))
  2351.          (rest-var (if restp (gensym)))
  2352.          (apply-fun (if restp 'APPLY 'FUNCALL))
  2353.          (apply-args `(,@req-vars ,@(if restp `(,rest-var) '())))
  2354.          (lambdalist `(,@req-vars ,@(if restp `(&REST ,rest-var) '())))
  2355.          (key-vars '())
  2356.          (lambdalist-with-key lambdalist)
  2357.          (arg-order (gf-argorder gf))
  2358.          (methods (gf-methods gf)))
  2359.     ; Determine the effective method:
  2360.     ; 1. Select the applicable methods:
  2361.     (setq methods
  2362.       (remove-if-not #'(lambda (method) (method-applicable-p method req-args))
  2363.                      methods
  2364.     ) )
  2365.     (when (null methods)
  2366.       (loop (apply #'no-applicable-method gf args))
  2367.     )
  2368.     ; 28.1.6.4., 28.1.6.5.: Keyword arguments in generic functions
  2369.     (when restp
  2370.       ; Die generische Funktion hat &REST oder &KEY, also auch alle Methoden.
  2371.       ; "If the lambda-list of ... the generic function definition contains
  2372.       ;  &allow-other-keys, all keyword arguments are accepted."
  2373.       (unless (fifth signature)
  2374.         ; "The specific set of keyword arguments accepted ... varies according
  2375.         ;  to the applicable methods."
  2376.         (let ((signatures (mapcar #'std-method-signature methods)))
  2377.           ; "A method that has &rest but not &key does not affect the set of
  2378.           ;  acceptable keyword srguments."
  2379.           (setq signatures (delete-if-not #'fourth signatures))
  2380.           ; Keine Methode mit &key -> keine Einschränkung der Argumente.
  2381.           (unless (null signatures)
  2382.             ; "If the lambda-list of any applicable method ... contains
  2383.             ;  &allow-other-keys, all keyword arguments are accepted."
  2384.             (unless (some #'sixth signatures)
  2385.               ; "The set of keyword arguments accepted for a particular call
  2386.               ;  is the union of the keyword arguments accepted by all
  2387.               ;  applicable methods and the keyword arguments mentioned after
  2388.               ;  &key in the generic function definition."
  2389.               (let ((keywords
  2390.                       (remove-duplicates
  2391.                         (append (fourth signature) (mapcap #'fifth signatures))
  2392.                         :from-end t
  2393.                    )) )
  2394.                 (setq key-vars (n-gensyms (length keywords)))
  2395.                 (setq lambdalist-with-key
  2396.                       `(,@lambdalist
  2397.                         &KEY
  2398.                         ,@(mapcar #'(lambda (kw var) `((,kw ,var)))
  2399.                                   keywords key-vars
  2400.                           )
  2401.                        )
  2402.     ) ) ) ) ) ) )
  2403.     ; 2. Sort the applicable methods by precedence order:
  2404.     (setq methods (sort-applicable-methods methods req-args arg-order))
  2405.     ; 3. Apply method combination:
  2406.     ; Nur STANDARD Methoden-Kombination ist implementiert.
  2407.     ; Aufspalten in einzelne Methoden-Typen:
  2408.     (multiple-value-bind (primary-methods before-methods after-methods around-methods)
  2409.         (partition-method-list methods)
  2410.       (when (null primary-methods)
  2411.         (loop (apply #'no-primary-method gf args))
  2412.       )
  2413.       ; Methoden zu einer "effektiven Methode" kombinieren:
  2414.       (labels ((ef-1 (primary-methods before-methods after-methods around-methods)
  2415.                  (if (null around-methods)
  2416.                    (ef-2 primary-methods before-methods after-methods)
  2417.                    (let* ((1method (first around-methods))
  2418.                           (1function (std-method-function 1method)))
  2419.                      (if (std-method-wants-next-method-p 1method)
  2420.                        (let ((next-ef
  2421.                                  (ef-1 primary-methods before-methods after-methods (rest around-methods))
  2422.                             ))
  2423.                          `(,apply-fun ',1function
  2424.                                       #'(LAMBDA ,lambdalist ,next-ef)
  2425.                                       ,@apply-args
  2426.                           )
  2427.                        )
  2428.                        `(,apply-fun ',1function ,@apply-args)
  2429.                ) ) ) )
  2430.                (ef-2 (primary-methods before-methods after-methods)
  2431.                  (let ((next-ef (ef-3 primary-methods after-methods)))
  2432.                    (if (null before-methods)
  2433.                      next-ef
  2434.                      `(PROGN
  2435.                         ,@(mapcar
  2436.                             #'(lambda (method)
  2437.                                 `(,apply-fun ',(std-method-function method)
  2438.                                              ,@apply-args
  2439.                                  )
  2440.                               )
  2441.                             before-methods ; most-specific-first
  2442.                           )
  2443.                         ,next-ef
  2444.                       )
  2445.                ) ) )
  2446.                (ef-3 (primary-methods after-methods)
  2447.                  (let ((next-ef (ef-4 primary-methods)))
  2448.                    (if (null after-methods)
  2449.                      next-ef
  2450.                      `(MULTIPLE-VALUE-PROG1
  2451.                         ,next-ef
  2452.                         ,@(mapcar
  2453.                             #'(lambda (method)
  2454.                                 `(,apply-fun ',(std-method-function method)
  2455.                                              ,@apply-args
  2456.                                  )
  2457.                               )
  2458.                             (reverse after-methods) ; most-specific-last
  2459.                           )
  2460.                       )
  2461.                ) ) )
  2462.                (ef-4 (primary-methods)
  2463.                  (let* ((1method (first primary-methods))
  2464.                         (1function (std-method-function 1method)))
  2465.                    (if (std-method-wants-next-method-p 1method)
  2466.                      (let ((next-ef-fun (ef-5 (rest primary-methods))))
  2467.                        `(,apply-fun ',1function ,next-ef-fun ,@apply-args)
  2468.                      )
  2469.                      `(,apply-fun ',1function ,@apply-args)
  2470.                ) ) )
  2471.                (ef-5 (primary-methods)
  2472.                  (if (null primary-methods)
  2473.                    'NIL ; keine Funktion, NEXT-METHOD-P reagiert darauf
  2474.                    `#'(LAMBDA ,lambdalist ,(ef-4 primary-methods))
  2475.               )) )
  2476.         (let* ((ef-form (ef-1 primary-methods before-methods after-methods around-methods))
  2477.                (ef-fun (if (and (eq (car ef-form) apply-fun)
  2478.                                 (equal (cddr ef-form) apply-args)
  2479.                                 (equal lambdalist lambdalist-with-key)
  2480.                            )
  2481.                          (cadr ef-form)
  2482.                          `#'(LAMBDA ,lambdalist-with-key
  2483.                               ,@(if key-vars `((DECLARE (IGNORE ,@key-vars))))
  2484.                               ,ef-form
  2485.                             )
  2486.               ))       )
  2487.           ; (eval ef-fun)                                 ; interpretiert
  2488.           ; (eval `(LOCALLY (DECLARE (COMPILE)) ,ef-fun)) ; compiliert
  2489.           (eval `(LET () (DECLARE (COMPILE) (INLINE FUNCALL APPLY)) ,ef-fun))
  2490. ) ) ) ) )
  2491.  
  2492.  
  2493. ; Grausamer Hack (28.1.9.2.):
  2494. ; MAKE-INSTANCE muß über die Methoden von INITIALIZE-INSTANCE und
  2495. ; SHARED-INITIALIZE Bescheid wissen.
  2496. ; REINITIALIZE-INSTANCE muß über die Methoden von REINITIALIZE-INSTANCE und
  2497. ; SHARED-INITIALIZE Bescheid wissen.
  2498. (defvar |#'initialize-instance| nil)
  2499. (defvar |#'reinitialize-instance| nil)
  2500. (defvar |#'shared-initialize| nil)
  2501.  
  2502. ; Hinzufügen einer Methode zu einer generischen Funktion:
  2503. (defun std-add-method (gf method)
  2504.   ; 28.1.6.4. congruent lambda lists
  2505.   (let ((gf-sign (gf-signature gf))             ; (reqanz optanz restp keywords allowp)
  2506.         (m-sign (std-method-signature method))) ; (reqanz optanz restp keyp keywords allowp)
  2507.     (unless (= (first m-sign) (first gf-sign))
  2508.       (error #+DEUTSCH "~S hat ~S, ~S hat aber ~S Required-Parameter."
  2509.              #+ENGLISH "~S has ~S, but ~S has ~S required parameters"
  2510.              method (first m-sign) gf (first gf-sign)
  2511.     ) )
  2512.     (unless (= (second m-sign) (second gf-sign))
  2513.       (error #+DEUTSCH "~S hat ~S, ~S hat aber ~S optionale Parameter."
  2514.              #+ENGLISH "~S has ~S, but ~S has ~S optional parameters"
  2515.              method (second m-sign) gf (second gf-sign)
  2516.     ) )
  2517.     (when (and (third m-sign) (not (third gf-sign)))
  2518.       (error #+DEUTSCH "~S hat &REST oder &KEY, ~S jedoch nicht."
  2519.              #+ENGLISH "~S has &REST or &KEY, but ~S hasn't."
  2520.              method gf
  2521.     ) )
  2522.     (when (and (third gf-sign) (not (third m-sign)))
  2523.       (error #+DEUTSCH "~S hat &REST oder &KEY, ~S jedoch nicht."
  2524.              #+ENGLISH "~S has &REST or &KEY, but ~S hasn't."
  2525.              gf method
  2526.     ) )
  2527.     (when (fourth gf-sign) ; gf hat Keywords?
  2528.       ; ja -> Methode muß sie akzeptieren:
  2529.       (unless (if (fourth m-sign) ; Methode hat &key ?
  2530.                 (or (sixth m-sign) ; Methode muß &allow-other-keys haben oder
  2531.                     (subsetp (fourth gf-sign) (fifth m-sign)) ; die Keywords aufzählen
  2532.                 )
  2533.                 (third m-sign) ; Methode muß &rest haben!
  2534.               )
  2535.         (error #+DEUTSCH "~S akzeptiert die Keywords ~S von ~S nicht."
  2536.                #+ENGLISH "~S doesn't accept the keywords ~S of ~S"
  2537.                method (fourth gf-sign) gf
  2538.     ) ) )
  2539.   )
  2540.   ; method kopieren, damit man gf eintragen kann:
  2541.   (when (std-method-wants-next-method-p method)
  2542.     (setq method (copy-standard-method method))
  2543.     (setf (std-method-function method) nil)
  2544.     (setf (std-method-gf method) gf)
  2545.   )
  2546.   ; function aus initfunction bestimmen:
  2547.   (when (null (std-method-function method))
  2548.     (let ((h (funcall (std-method-initfunction method) method)))
  2549.       (setf (std-method-function method) (car h))
  2550.       (when (car (cdr h)) ; konnte die Variable ",cont" wegoptimiert werden?
  2551.         (setf (std-method-wants-next-method-p method) nil)
  2552.   ) ) )
  2553.   ; Methode ist fertig. Eintragen:
  2554.   (warn-if-gf-already-called gf)
  2555.   (let ((old-method (find method (gf-methods gf) :test #'methods-agree-p)))
  2556.     (cond ((eq gf |#'initialize-instance|) (note-ii-change method))
  2557.           ((eq gf |#'reinitialize-instance|) (note-ri-change method))
  2558.           ((eq gf |#'shared-initialize|) (note-si-change method))
  2559.     )
  2560.     (setf (gf-methods gf)
  2561.           (cons method
  2562.                 (if old-method
  2563.                   (progn
  2564.                     (warn #+DEUTSCH "Methode ~S in ~S wird ersetzt."
  2565.                           #+ENGLISH "Replacing method ~S in ~S"
  2566.                           old-method gf
  2567.                     )
  2568.                     (remove old-method (gf-methods gf))
  2569.                   )
  2570.                   (gf-methods gf)
  2571.     )     )     )
  2572.     (finalize-fast-gf gf)
  2573.   )
  2574.   gf
  2575. )
  2576.  
  2577. ; Entfernen einer Methode von einer generischen Funktion:
  2578. (defun std-remove-method (gf method)
  2579.   (let ((old-method (find method (gf-methods gf) :key #'std-method-initfunction)))
  2580.     (when old-method
  2581.       (warn-if-gf-already-called gf)
  2582.       (warn #+DEUTSCH "Methode ~S in ~S wird entfernt."
  2583.             #+ENGLISH "Removing method ~S in ~S"
  2584.             old-method gf
  2585.       )
  2586.       (cond ((eq gf |#'initialize-instance|) (note-ii-change method))
  2587.             ((eq gf |#'reinitialize-instance|) (note-ri-change method))
  2588.             ((eq gf |#'shared-initialize|) (note-si-change method))
  2589.       )
  2590.       (setf (gf-methods gf) (remove old-method (gf-methods gf)))
  2591.       (finalize-fast-gf gf)
  2592.   ) )
  2593.   gf
  2594. )
  2595.  
  2596. ; Aufsuchen einer Methode in einer generischen Funktion:
  2597. (defun std-find-method (gf qualifiers specializers &optional (errorp t))
  2598.   ; sozusagen
  2599.   ;   (find hypothetical-method (gf-methods gf) :test #'methods-agree-p)
  2600.   ; vgl. methods-agree-p
  2601.   (dolist (method (gf-methods gf))
  2602.     (when (and (equal (std-method-qualifiers method) qualifiers)
  2603.                (specializers-agree-p (std-method-parameter-specializers method)
  2604.                                      specializers
  2605.           )    )
  2606.       (return-from std-find-method method)
  2607.   ) )
  2608.   (if errorp
  2609.     (error #+DEUTSCH "~S hat keine Methode mit Bestimmern ~:S und Spezialierung ~S."
  2610.            #+ENGLISH "~S has no method with qualifiers ~:S and specializers ~S"
  2611.            gf qualifiers specializers
  2612.     )
  2613.     nil
  2614. ) )
  2615.  
  2616.  
  2617. ;;; DEFMETHOD
  2618.  
  2619. (defmacro defmethod (funname &rest method-description &environment env)
  2620.   (unless (function-name-p funname)
  2621.     (error #+DEUTSCH "~S: Der Name einer Funktion muß ein Symbol sein, nicht: ~S"
  2622.            #+ENGLISH "~S: the name of a function must be a symbol, not ~S"
  2623.            #+FRANCAIS "~S : Le nom d'une fonction doit être un symbole et non ~S"
  2624.            'defmethod funname
  2625.   ) )
  2626.   `(LET ()
  2627.      (EVAL-WHEN (COMPILE) (COMPILER::C-DEFUN ',funname))
  2628.      (DO-DEFMETHOD ',funname
  2629.        ,(analyze-method-description 'defmethod funname method-description env)
  2630.    ) )
  2631. )
  2632.  
  2633. (defun do-defmethod (funname method)
  2634.   (std-add-method
  2635.     (if (fboundp funname)
  2636.       (let ((gf (fdefinition funname)))
  2637.         (if (clos::generic-function-p gf)
  2638.           gf
  2639.           (error #+DEUTSCH "~S bezeichnet keine generische Funktion."
  2640.                  #+ENGLISH "~S doesn't name a generic function"
  2641.                  funname
  2642.       ) ) )
  2643.       (setf (fdefinition funname)
  2644.             (let ((signature (std-method-signature method)))
  2645.               (make-fast-gf funname
  2646.                             ; GF-Signatur aus der Methoden-Signatur bestimmen:
  2647.                             (list (first signature) ; reqanz
  2648.                                   (second signature) ; optanz
  2649.                                   (third signature) ; restp
  2650.                                   '() ; keywords
  2651.                                   nil ; allowp
  2652.                             )
  2653.                             ; argorder := (0 ... reqanz-1)
  2654.                             (countup (first signature))
  2655.       )     ) )
  2656.     )
  2657.     method
  2658.   )
  2659.   method
  2660. )
  2661.  
  2662. ; n --> Liste (0 ... n-1)
  2663. (defun countup (n)
  2664.   (do* ((count n (1- count))
  2665.         (l '() (cons count l)))
  2666.        ((eql count 0) l)
  2667. ) )
  2668.  
  2669.  
  2670. ;; Für DEFGENERIC, GENERIC-FUNCTION, GENERIC-FLET, GENERIC-LABELS,
  2671. ;; WITH-ADDED-METHODS
  2672.   ; caller: Symbol
  2673.   ; funname: Funktionsname, Symbol oder (SETF symbol)
  2674.   ; lambdalist: Lambdaliste der generischen Funktion
  2675.   ; options: (option*)
  2676.   ; --> signature, argorder, method-forms, docstring
  2677. (defun analyze-defgeneric (caller funname lambdalist options env)
  2678.   (unless (function-name-p funname)
  2679.     (error #+DEUTSCH "~S: Der Name einer Funktion muß ein Symbol sein, nicht: ~S"
  2680.            #+ENGLISH "~S: the name of a function must be a symbol, not ~S"
  2681.            #+FRANCAIS "~S : Le nom d'une fonction doit être un symbole et non ~S"
  2682.            caller funname lambdalist
  2683.   ) )
  2684.   ; Lambdaliste parsen:
  2685.   (multiple-value-bind (reqanz req-vars optanz restp keywords allowp)
  2686.       (analyze-defgeneric-lambdalist caller funname lambdalist)
  2687.     ; Optionen abarbeiten:
  2688.     (let ((method-forms '())
  2689.           (argorders nil)
  2690.           (docstrings nil))
  2691.       (dolist (option options)
  2692.         (unless (listp option)
  2693.           (error #+DEUTSCH "~S ~S: Das ist keine ~S-Option: ~S"
  2694.                  #+ENGLISH "~S ~S: not a ~S option: ~S"
  2695.                  #+FRANCAIS "~S ~S : Ceci n'est pas une option ~S: ~S"
  2696.                  caller funname 'defgeneric option
  2697.         ) )
  2698.         (case (first option)
  2699.           (DECLARE
  2700.             (unless (every
  2701.                        #'(lambda (x) (and (consp x) (eq (first x) 'OPTIMIZE)))
  2702.                        (rest option)
  2703.                     )
  2704.               (error #+DEUTSCH "~S ~S: Erlaubt sind nur ~S-Deklarationen: ~S"
  2705.                      #+ENGLISH "~S ~S: Only ~S declarations are permitted: ~S"
  2706.                      caller funname 'optimize option
  2707.             ) )
  2708.             ; Die Deklaration wird ignoriert.
  2709.             ; Der Compiler ignoriert sie sowieso.
  2710.           )
  2711.           (:ARGUMENT-PRECEDENCE-ORDER
  2712.             (when argorders
  2713.               (error #+DEUTSCH "~S ~S: ~S darf nur einmal angegeben werden."
  2714.                      #+ENGLISH "~S ~S: ~S may only be specified once."
  2715.                      caller funname ':argument-precedence-order
  2716.             ) )
  2717.             (setq argorders option)
  2718.           )
  2719.           (:DOCUMENTATION
  2720.             (unless (and (eql (length option) 2) (stringp (second option)))
  2721.               (error #+DEUTSCH "~S ~S: Nach ~S muß ein String angegeben werden: ~S"
  2722.                      #+ENGLISH "~S ~S: A string must be specified after ~S : ~S"
  2723.                      caller funname ':documentation option
  2724.             ) )
  2725.             (when docstrings
  2726.               (error #+DEUTSCH "~S ~S: Es ist höchstens ein ~S-String erlaubt."
  2727.                      #+ENGLISH "~S ~S: Only one ~S string is allowed"
  2728.                      caller funname ':documentation
  2729.             ) )
  2730.             (setq docstrings (rest option))
  2731.           )
  2732.           (:METHOD-COMBINATION
  2733.             (unless (equal (rest option) '(STANDARD))
  2734.               (error #+DEUTSCH "~S ~S: Als Methodenkombination ist nur ~S zugelassen: ~S"
  2735.                      #+ENGLISH "~S ~S: The only valid method combination is ~S : ~S"
  2736.                      caller funname 'standard option
  2737.             ) )
  2738.             ; Die Methodenkombination wird ignoriert.
  2739.           )
  2740.           (:GENERIC-FUNCTION-CLASS
  2741.             (unless (equal (rest option) '(STANDARD-GENERIC-FUNCTION))
  2742.               (error #+DEUTSCH "~S ~S: Als Name der Klasse der generischen Funktion ist nur ~S zugelassen: ~S"
  2743.                      #+ENGLISH "~S ~S: The only valid generic function class name is ~S : ~S"
  2744.                      caller funname 'standard-generic-function option
  2745.             ) )
  2746.             ; Die Klasse der generischen Funktion wird ignoriert.
  2747.           )
  2748.           (:METHOD-CLASS
  2749.             (unless (equal (rest option) '(STANDARD-METHOD))
  2750.               (error #+DEUTSCH "~S ~S: Als Name der Klasse der Methoden ist nur ~S zugelassen: ~S"
  2751.                      #+ENGLISH "~S ~S: The only valid method class name is ~S : ~S"
  2752.                      caller funname 'standard-method option
  2753.             ) )
  2754.             ; Die Klasse der Methoden wird ignoriert.
  2755.           )
  2756.           (:METHOD
  2757.             (push (analyze-method-description caller funname (rest option) env)
  2758.                   method-forms
  2759.           ) )
  2760.           (t (error #+DEUTSCH "~S ~S: Falsche Syntax in ~S-Option: ~S"
  2761.                     #+ENGLISH "~S ~S: invalid syntax in ~S option: ~S"
  2762.                     #+FRANCAIS "~S ~S : Mauvaise syntaxe dans l'option ~S: ~S"
  2763.                     caller funname 'defstruct option
  2764.       ) ) )  )
  2765.       ; :argument-precedence-order überprüfen:
  2766.       (let ((argorder
  2767.               (if argorders
  2768.                 (let ((l (mapcar #'(lambda (x)
  2769.                                      (or (position x req-vars)
  2770.                                          (error #+DEUTSCH "~S ~S: ~S ist keiner der notwendigen Parameter: ~S"
  2771.                                                 #+ENGLISH "~S ~S: ~S is not one of the required parameters: ~S"
  2772.                                                 caller funname x argorders
  2773.                                    ) )   )
  2774.                                  (rest argorders)
  2775.                      ))  )
  2776.                   ; Ist (rest argorders) eine Permutation von req-vars ?
  2777.                   ; Anders ausgedrückt: Ist die Abbildung
  2778.                   ;        (rest argorders)  -->  req-vars
  2779.                   ; bzw.   l --> {0, ..., reqanz-1}
  2780.                   ; bijektiv?
  2781.                   (unless (apply #'/= l) ; injektiv?
  2782.                     (error #+DEUTSCH "~S ~S: eine Variable taucht in ~S doppelt auf."
  2783.                            #+ENGLISH "~S ~S: some variable occurs twice in ~S"
  2784.                            caller funname argorders
  2785.                   ) )
  2786.                   (unless (eql (length l) reqanz) ; surjektiv?
  2787.                     (error #+DEUTSCH "~S ~S: ~S enthält nicht alle notwendigen Parameter."
  2788.                            #+ENGLISH "~S ~S: ~S is missing some required parameter"
  2789.                            caller funname argorders
  2790.                   ) )
  2791.                   l
  2792.                 )
  2793.                 (countup reqanz)
  2794.            )) )
  2795.         (values ; Signatur
  2796.                 `(,reqanz ,optanz ,restp ,keywords ,allowp)
  2797.                 ; argorder
  2798.                 argorder
  2799.                 ; Liste der Methoden-Formen
  2800.                 (nreverse method-forms)
  2801.                 ; docstring oder nil
  2802.                 (car docstrings)
  2803.         )
  2804. ) ) ) )
  2805.  
  2806. ; Lambdaliste parsen:
  2807. ; lambdalist --> reqanz, req-vars, optanz, restp, keywords, allowp
  2808. (defun analyze-defgeneric-lambdalist (caller funname lambdalist)
  2809.   (let ((req-vars '())
  2810.         (optanz 0)
  2811.         (restp nil)
  2812.         (keyp nil)
  2813.         (keywords '())
  2814.         (allowp nil))
  2815.     (when (some #'(lambda (item) (and (consp item) (cdr item))) lambdalist)
  2816.       (error #+DEUTSCH "~S ~S: In der Lambda-Liste einer generischen Funktion sind keine Initialisierungen erlaubt: ~S"
  2817.              #+ENGLISH "~S ~S: No initializations are allowed in a generic function lambda-list: ~S"
  2818.              caller funname lambdalist
  2819.     ) )
  2820.     (flet ((check-varname (var)
  2821.              (unless (symbolp var)
  2822.                (error #+DEUTSCH "~S ~S: Variablenname muß ein Symbol sein, nicht ~S"
  2823.                       #+ENGLISH "~S ~S: variable name ~S should be a symbol"
  2824.                       caller funname var
  2825.              ) )
  2826.              (when (member var req-vars :test #'eq)
  2827.                (error #+DEUTSCH "~S ~S: Variablenname ~S darf nicht mehrfach auftreten."
  2828.                       #+ENGLISH "~S ~S: duplicate variable name ~S"
  2829.                       caller funname var
  2830.              ) )
  2831.              var
  2832.           ))
  2833.       (loop
  2834.         (when (or (atom lambdalist) (lambda-list-keyword-p (first lambdalist)))
  2835.           (return)
  2836.         )
  2837.         (push (check-varname (pop lambdalist)) req-vars)
  2838.       )
  2839.       (when (and (consp lambdalist) (eq (first lambdalist) '&optional))
  2840.         (pop lambdalist)
  2841.         (loop
  2842.           (when (or (atom lambdalist) (lambda-list-keyword-p (first lambdalist)))
  2843.             (return)
  2844.           )
  2845.           (let ((item (pop lambdalist)))
  2846.             (check-varname (if (consp item) (first item) item))
  2847.             (incf optanz)
  2848.       ) ) )
  2849.       (when (and (consp lambdalist) (eq (first lambdalist) '&rest)
  2850.                  (consp (rest lambdalist))
  2851.             )
  2852.         (pop lambdalist)
  2853.         (check-varname (pop lambdalist))
  2854.         (setq restp t)
  2855.       )
  2856.       (when (and (consp lambdalist) (eq (first lambdalist) '&key))
  2857.         (pop lambdalist)
  2858.         (loop
  2859.           (when (or (atom lambdalist) (lambda-list-keyword-p (first lambdalist)))
  2860.             (return)
  2861.           )
  2862.           (let ((item (pop lambdalist)))
  2863.             (when (consp item) (setq item (first item)))
  2864.             (check-varname (if (consp item) (second item) item))
  2865.             (push (if (consp item)
  2866.                     (first item)
  2867.                     (intern (symbol-name item) *keyword-package*)
  2868.                   )
  2869.                   keywords
  2870.         ) ) )
  2871.         (when (and (consp lambdalist) (eq (first lambdalist) '&allow-other-keys))
  2872.           (pop lambdalist)
  2873.           (setq allowp t)
  2874.       ) )
  2875.     )
  2876.     (when lambdalist
  2877.       (error #+DEUTSCH "~S ~S: Lambda-Liste enthält Unzulässiges: ~S"
  2878.              #+ENGLISH "~S ~S: invalid lambda list portion: ~S"
  2879.              caller funname lambdalist
  2880.     ) )
  2881.     (values (length req-vars) (nreverse req-vars) optanz
  2882.             (or restp keyp) keywords allowp
  2883. ) ) )
  2884.  
  2885. ; Lambdaliste in Aufrufkonvention umrechnen:
  2886. (defun defgeneric-lambdalist-callinfo (caller funname lambdalist)
  2887.   (multiple-value-bind (reqanz req-vars optanz restp keywords allowp)
  2888.       (analyze-defgeneric-lambdalist caller funname lambdalist)
  2889.     (declare (ignore req-vars))
  2890.     (callinfo reqanz optanz restp keywords allowp)
  2891. ) )
  2892.  
  2893.  
  2894. ;;; DEFGENERIC
  2895.  
  2896. (defmacro defgeneric (funname lambda-list &rest options &environment env)
  2897.   (multiple-value-bind (signature argorder method-forms docstring)
  2898.       (analyze-defgeneric 'defgeneric funname lambda-list options env)
  2899.     `(LET ()
  2900.        (EVAL-WHEN (COMPILE) (COMPILER::C-DEFUN ',funname))
  2901.        ; NB: Kein (SYSTEM::REMOVE-OLD-DEFINITIONS ',funname)
  2902.        ,@(if docstring
  2903.            (let ((symbolform
  2904.                    (if (atom funname)
  2905.                      `',funname
  2906.                      `(LOAD-TIME-VALUE (GET-SETF-SYMBOL ',(second funname)))
  2907.                 )) )
  2908.              `((SYSTEM::%SET-DOCUMENTATION ,symbolform 'FUNCTION ',docstring))
  2909.          ) )
  2910.        (DO-DEFGENERIC ',funname ',signature ',argorder ,@method-forms)
  2911.      )
  2912. ) )
  2913.  
  2914. (defun make-generic-function (funname signature argorder &rest methods)
  2915.   (let ((gf (make-fast-gf funname signature argorder)))
  2916.     (dolist (method methods) (std-add-method gf method))
  2917.     (finalize-fast-gf gf)
  2918.     gf
  2919. ) )
  2920.  
  2921. (defun do-defgeneric (funname signature argorder &rest methods)
  2922.   (if (fboundp funname)
  2923.     (let ((gf (fdefinition funname)))
  2924.       (if (clos::generic-function-p gf)
  2925.         ; Umdefinition einer generischen Funktion
  2926.         (progn
  2927.           (warn-if-gf-already-called gf)
  2928.           (unless (null (gf-methods gf))
  2929.             (warn #+DEUTSCH "Alle Methoden von ~S werden entfernt."
  2930.                   #+ENGLISH "Removing all methods of ~S"
  2931.                   gf
  2932.             )
  2933.             (setf (gf-methods gf) nil)
  2934.           )
  2935.           (unless (and (equal signature (gf-signature gf))
  2936.                        (equal argorder (gf-argorder gf))
  2937.                   )
  2938.             (warn #+DEUTSCH "Das Parameter-Profil von ~S wird modifiziert."
  2939.                   #+ENGLISH "Modifying the parameter profile of ~S"
  2940.                   gf
  2941.             )
  2942.             (setf (gf-signature gf) signature)
  2943.             (setf (gf-argorder gf) argorder)
  2944.           )
  2945.           (dolist (method methods) (std-add-method gf method))
  2946.           (finalize-fast-gf gf)
  2947.           gf
  2948.         )
  2949.         (error #+DEUTSCH "~S bezeichnet keine generische Funktion."
  2950.                #+ENGLISH "~S doesn't name a generic function"
  2951.                funname
  2952.     ) ) )
  2953.     (setf (fdefinition funname)
  2954.           (apply #'make-generic-function funname signature argorder methods)
  2955. ) ) )
  2956.  
  2957.  
  2958. #|
  2959. ;; Für GENERIC-FLET, GENERIC-LABELS
  2960.  
  2961. ; Wie make-generic-function, nur daß der Dispatch-Code gleich installiert wird.
  2962. (defun make-generic-function-now (funname signature argorder &rest methods)
  2963.   (let ((gf (make-fast-gf funname signature argorder)))
  2964.     (dolist (method methods) (std-add-method gf method))
  2965.     (install-dispatch gf)
  2966.     gf
  2967. ) )
  2968. |#
  2969.  
  2970.  
  2971. ;; Für GENERIC-FUNCTION, GENERIC-FLET, GENERIC-LABELS
  2972.  
  2973. (defun make-generic-function-form (caller funname lambda-list options env)
  2974.   (multiple-value-bind (signature argorder method-forms docstring)
  2975.       (analyze-defgeneric caller funname lambda-list options env)
  2976.     (declare (ignore docstring))
  2977.     `(MAKE-GENERIC-FUNCTION ',funname ',signature ',argorder ,@method-forms)
  2978. ) )
  2979.  
  2980.  
  2981. ;;; GENERIC-FUNCTION
  2982.  
  2983. (defmacro generic-function (lambda-list &rest options &environment env)
  2984.   (make-generic-function-form 'generic-function 'LAMBDA lambda-list options env)
  2985. )
  2986.  
  2987.  
  2988. ;; Für GENERIC-FLET, GENERIC-LABELS
  2989. (defun analyze-generic-fundefs (caller fundefs env)
  2990.   (let ((names '())
  2991.         (funforms '()))
  2992.     (dolist (fundef fundefs)
  2993.       (unless (and (consp fundef) (consp (cdr fundef)))
  2994.         (error #+DEUTSCH "~S: ~S ist keine Spezifikation einer generischen Funktion."
  2995.                #+ENGLISH "~S: ~S is not a generic function specification"
  2996.                #+FRANCAIS "~S: ~S n'est pas une spécification de fonction générique."
  2997.                caller fundef
  2998.       ) )
  2999.       (push (first fundef) names)
  3000.       (push (make-generic-function-form caller (first fundef) (second fundef) (cddr fundef) env) funforms)
  3001.     )
  3002.     (values (nreverse names) (nreverse funforms))
  3003. ) )
  3004.  
  3005.  
  3006. ;;; GENERIC-FLET
  3007.  
  3008. (defmacro generic-flet (fundefs &body body &environment env)
  3009.   (multiple-value-bind (funnames funforms)
  3010.       (analyze-generic-fundefs 'generic-flet fundefs env)
  3011.     (let ((varnames (n-gensyms (length funnames))))
  3012.       `(LET ,(mapcar #'list varnames funforms)
  3013.          (FLET ,(mapcar #'(lambda (varname funname)
  3014.                             `(,funname (&rest args) (apply ,varname args))
  3015.                           )
  3016.                         varnames funnames
  3017.                 )
  3018.            ,@body
  3019.        ) )
  3020. ) ) )
  3021.  
  3022.  
  3023. ;;; GENERIC-LABELS
  3024.  
  3025. (defmacro generic-labels (fundefs &body body &environment env)
  3026.   (multiple-value-bind (funnames funforms)
  3027.       (analyze-generic-fundefs 'generic-labels fundefs env)
  3028.     (let ((varnames (n-gensyms (length funnames))))
  3029.       `(LET ,varnames
  3030.          (FLET ,(mapcar #'(lambda (varname funname)
  3031.                             `(,funname (&rest args) (apply ,varname args))
  3032.                           )
  3033.                         varnames funnames
  3034.                 )
  3035.            ,@(mapcar #'(lambda (varname funform) `(SETQ ,varname ,funform))
  3036.                      varnames funforms
  3037.              )
  3038.            ,@body
  3039.        ) )
  3040. ) ) )
  3041.  
  3042.  
  3043. ;;; WITH-ADDED-METHODS
  3044. ; ist vermurkst und wird deshalb nicht implementiert.
  3045.  
  3046.  
  3047. ;;; Verschiedene generische Funktionen, die wir bis jetzt hinausgezögert haben:
  3048.  
  3049. (defgeneric class-name (class)
  3050.   (:method ((class class))
  3051.     (class-classname class)
  3052. ) )
  3053.  
  3054. (defgeneric (setf class-name) (new-value class)
  3055.   (:method (new-value (class class))
  3056.     (unless (symbolp new-value)
  3057.       (error #+DEUTSCH "~S: Der Name einer Klasse muß ein Symbol sein, nicht ~S"
  3058.              #+ENGLISH "~S: The name of a class must be a symbol, not ~S"
  3059.              '(setf class-name) new-value
  3060.     ) )
  3061.     (when (built-in-class-p class)
  3062.       (error #+DEUTSCH "~S: Der Name der Built-In-Klasse ~S kann nicht verändert werden."
  3063.              #+ENGLISH "~S: The name of the built-in class ~S cannot be modified"
  3064.              '(setf class-name) class
  3065.     ) )
  3066.     (setf (class-classname class) new-value)
  3067. ) )
  3068.  
  3069. (defgeneric no-applicable-method (gf &rest args)
  3070.   (:method ((gf t) &rest args)
  3071.     (error #+DEUTSCH "~S: Beim Aufruf von ~S mit Argumenten ~S ist keine Methode anwendbar."
  3072.            #+ENGLISH "~S: When calling ~S with arguments ~S, no method is applicable."
  3073.            'no-applicable-method gf args
  3074. ) ) )
  3075.  
  3076. (defgeneric no-primary-method (gf &rest args)
  3077.   (:method ((gf t) &rest args)
  3078.     (error #+DEUTSCH "~S: Beim Aufruf von ~S mit Argumenten ~S ist keine primäre Methode anwendbar."
  3079.            #+ENGLISH "~S: When calling ~S with arguments, no primary method is applicable."
  3080.            'no-primary-method gf args
  3081. ) ) )
  3082.  
  3083. (defun %no-next-method (method &rest args)
  3084.   (apply #'no-next-method (std-method-gf method) method args)
  3085. )
  3086. (defgeneric no-next-method (gf method &rest args)
  3087.   (:method ((gf standard-generic-function) (method standard-method) &rest args)
  3088.     (error #+DEUTSCH "~S: Beim Aufruf von ~S mit Argumenten ~S gibt es nach ~S keine weitere Methode, und ~S wurde aufgerufen."
  3089.            #+ENGLISH "~S: When calling ~S with arguments, there is no next method after ~S, and ~S was called."
  3090.            'no-next-method gf args method '(call-next-method)
  3091. ) ) )
  3092.  
  3093. (defgeneric find-method (gf qualifiers specializers &optional errorp)
  3094.   (:method ((gf standard-generic-function) qualifiers specializers &optional (errorp t))
  3095.      (std-find-method gf qualifiers specializers errorp)
  3096. ) )
  3097.  
  3098. (defgeneric add-method (gf method)
  3099.   (:method ((gf standard-generic-function) (method standard-method))
  3100.     (std-add-method gf method)
  3101. ) )
  3102.  
  3103. (defgeneric remove-method (gf method)
  3104.   (:method ((gf standard-generic-function) (method standard-method))
  3105.     (std-remove-method gf method)
  3106. ) )
  3107.  
  3108. (defun compute-applicable-methods (gf args)
  3109.   (let ((reqanz (first (gf-signature gf)))
  3110.         (methods (gf-methods gf)))
  3111.     (if (>= (length args) reqanz)
  3112.       (let ((req-args (subseq args 0 reqanz)))
  3113.         ; 1. Select the applicable methods:
  3114.         (setq methods
  3115.           (remove-if-not
  3116.             #'(lambda (method) (method-applicable-p method req-args))
  3117.             methods
  3118.         ) )
  3119.         ; 2. Sort the applicable methods by precedence order:
  3120.         (sort-applicable-methods methods req-args (gf-argorder gf))
  3121.       )
  3122.       nil ; lieber kein Error
  3123. ) ) )
  3124.  
  3125. (defgeneric method-qualifiers (method)
  3126.   (:method ((method standard-method))
  3127.     (std-method-qualifiers method)
  3128. ) )
  3129.  
  3130. (defgeneric function-keywords (method)
  3131.   (:method ((method standard-method))
  3132.     (values-list (cddddr (std-method-signature method)))
  3133. ) )
  3134.  
  3135. (defgeneric slot-missing (class instance slot-name operation &optional new-value)
  3136.   (:method ((class t) instance slot-name operation &optional new-value)
  3137.     (declare (ignore instance new-value))
  3138.     (error #+DEUTSCH "~S: Die Klasse ~S hat keinen Slot mit Namen ~S."
  3139.            #+ENGLISH "~S: The class ~S has no slot named ~S"
  3140.            operation class slot-name
  3141. ) ) )
  3142.  
  3143. (defgeneric slot-unbound (class instance slot-name)
  3144.   (:method ((class t) instance slot-name)
  3145.     (declare (ignore class))
  3146.     (error #+DEUTSCH "~S: Der Slot ~S von ~S hat keinen Wert."
  3147.            #+ENGLISH "~S: The slot ~S of ~S has no value"
  3148.            'slot-value slot-name instance
  3149. ) ) )
  3150.  
  3151. (defgeneric print-object (object stream)
  3152.   (:method ((object standard-object) stream)
  3153.     (print-unreadable-object (object stream :type t :identity t))
  3154. ) )
  3155.  
  3156. (defgeneric describe-object (object stream)
  3157.   (:method ((object standard-object) s)
  3158.     (let ((slotnames (mapcar #'slotdef-name (class-slots (class-of object)))))
  3159.       (if slotnames
  3160.         (let* ((slotstrings (mapcar #'write-to-string slotnames))
  3161.                (tabpos (+ 4 (reduce #'max (mapcar #'length slotstrings)))))
  3162.           (format s #+DEUTSCH "~%Slots:"
  3163.                     #+ENGLISH "~%Slots:"
  3164.           )
  3165.           (mapc #'(lambda (slotname slotstring)
  3166.                     (format s "~%  ~A~VT" slotstring tabpos)
  3167.                     (if (slot-boundp object slotname)
  3168.                       (format s "=  ~S" (slot-value object slotname))
  3169.                       (format s #+DEUTSCH "ohne Wert"
  3170.                                 #+ENGLISH "unbound"
  3171.                   ) ) )
  3172.                 slotnames slotstrings
  3173.         ) )
  3174.         (format s #+DEUTSCH "~%Keine Slots."
  3175.                   #+ENGLISH "~%No slots."
  3176.   ) ) ) )
  3177. )
  3178.  
  3179.  
  3180. ;; 28.1.9. Object creation and initialization
  3181.  
  3182. ; Grausamer Hack (28.1.9.2.):
  3183. ; MAKE-INSTANCE muß über die Methoden von INITIALIZE-INSTANCE und
  3184. ; SHARED-INITIALIZE Bescheid wissen.
  3185. ; REINITIALIZE-INSTANCE muß über die Methoden von REINITIALIZE-INSTANCE und
  3186. ; SHARED-INITIALIZE Bescheid wissen.
  3187.  
  3188. (defparameter *make-instance-table* (make-hash-table :test #'eq))
  3189.   ; Hashtabelle, die einer Klasse zuordnet ein List* aus
  3190.   ; - einer Liste der zulässigen Keyword-Argumente,
  3191.   ; - der effektiven Methode von initialize-instance,
  3192.   ; - der effektiven Methode von shared-initialize.
  3193.  
  3194. (defparameter *reinitialize-instance-table* (make-hash-table :test #'eq))
  3195.   ; Hashtabelle, die einer Klasse zuordnet ein Cons aus
  3196.   ; - einer Liste der zulässigen Keyword-Argumente,
  3197.   ; - der effektiven Methode von shared-initialize.
  3198.  
  3199. (defun note-i-change (specializer table)
  3200.   (maphash #'(lambda (class value) (declare (ignore value))
  3201.                (when (subclassp class specializer)
  3202.                  (remhash class table)
  3203.              ) )
  3204.            table
  3205. ) )
  3206.  
  3207. (defun note-ii-change (method)
  3208.   (let ((specializer (first (std-method-parameter-specializers method))))
  3209.     ; EQL-Methoden auf INITIALIZE-INSTANCE sind eh wertlos
  3210.     (unless (consp specializer)
  3211.       ; Entferne die Einträge von *make-instance-table*, für welche die
  3212.       ; besagte Methode anwendbar wäre:
  3213.       (note-i-change specializer *make-instance-table*)
  3214. ) ) )
  3215.  
  3216. (defun note-ri-change (method)
  3217.   (let ((specializer (first (std-method-parameter-specializers method))))
  3218.     ; EQL-Methoden auf REINITIALIZE-INSTANCE sind im wesentlichen wertlos
  3219.     (unless (consp specializer)
  3220.       ; Entferne die Einträge von *reinitialize-instance-table*, für welche die
  3221.       ; besagte Methode anwendbar wäre:
  3222.       (note-i-change specializer *reinitialize-instance-table*)
  3223. ) ) )
  3224.  
  3225. (defun note-si-change (method)
  3226.   (let* ((specializers (std-method-parameter-specializers method))
  3227.          (specializer1 (first specializers))
  3228.          (specializer2 (second specializers)))
  3229.     ; EQL-Methoden auf SHARED-INITIALIZE sind im wesentlichen wertlos
  3230.     (unless (consp specializer1)
  3231.       ; Als zweites Argument wird von INITIALIZE-INSTANCE immer nur T übergeben.
  3232.       (when (typep 'T specializer2)
  3233.         ; Entferne die Einträge von *make-instance-table*, für welche die
  3234.         ; besagte Methode anwendbar wäre:
  3235.         (note-i-change specializer1 *make-instance-table*)
  3236.       )
  3237.       ; Als zweites Argument wird von REINITIALIZE-INSTANCE nur NIL übergeben.
  3238.       (when (typep 'NIL specializer2)
  3239.         ; Entferne die Einträge von *reinitialize-instance-table*, für welche die
  3240.         ; besagte Methode anwendbar wäre:
  3241.         (note-i-change specializer1 *reinitialize-instance-table*)
  3242.       )
  3243. ) ) )
  3244.  
  3245. ; Aus einer Liste von anwendbaren Methoden alle Keywords sammeln:
  3246. (defun valid-initarg-keywords (class methods)
  3247.   (let ((signatures (mapcar #'std-method-signature methods)))
  3248.     ; "A method that has &rest but not &key does not affect the set of
  3249.     ;  acceptable keyword srguments."
  3250.     (setq signatures (delete-if-not #'fourth signatures))
  3251.     ; "The keyword name of each keyword parameter specified in the method's
  3252.     ;  lambda-list becomes an initialization argument for all classes for
  3253.     ;  which the method is applicable."
  3254.     (remove-duplicates
  3255.       (append (class-valid-initargs class) (mapcap #'fifth signatures))
  3256.       :from-end t
  3257. ) ) )
  3258.  
  3259. ; NB: Beim Berechnen einer effektiven Methode kommt es auf die restlichen
  3260. ; Argumente nicht an.
  3261. ; Beim ersten INITIALIZE-INSTANCE- oder MAKE-INSTANCE-Aufruf einer jeden Klasse
  3262. ; merkt man sich die benötigte Information in *make-instance-table*.
  3263.  
  3264. ; Bei MAKE-INSTANCE sind als Keys gültig:
  3265. ; - die Initargs, die zur Initialisierung von Slots benutzt werden,
  3266. ; - die Keywords von Methoden von SHARED-INITIALIZE,
  3267. ; - die Keywords von Methoden von INITIALIZE-INSTANCE.
  3268. (defun valid-make-instance-keywords (class)
  3269.   (valid-initarg-keywords
  3270.     class
  3271.     (append
  3272.       ; Liste aller anwendbaren Methoden von SHARED-INITIALIZE
  3273.       (remove-if-not
  3274.         #'(lambda (method)
  3275.             (let* ((specializers (std-method-parameter-specializers method))
  3276.                    (specializer1 (first specializers))
  3277.                    (specializer2 (second specializers)))
  3278.               (and (atom specializer1) (subclassp class specializer1)
  3279.                    (typep 'T specializer2)
  3280.           ) ) )
  3281.         (gf-methods |#'shared-initialize|)
  3282.       )
  3283.       ; Liste aller anwendbaren Methoden von INITIALIZE-INSTANCE
  3284.       (remove-if-not
  3285.         #'(lambda (method)
  3286.             (let ((specializer (first (std-method-parameter-specializers method))))
  3287.               (and (atom specializer) (subclassp class specializer))
  3288.           ) )
  3289.         (gf-methods |#'initialize-instance|)
  3290.       )
  3291. ) ) )
  3292. (defun make-instance-table-entry2 (instance)
  3293.   (cons (compute-effective-method |#'initialize-instance| instance)
  3294.         (compute-effective-method |#'shared-initialize| instance 'T)
  3295. ) )
  3296.  
  3297. ; 28.1.9.5., 28.1.9.4.
  3298. (defgeneric shared-initialize (instance slot-names &rest initargs))
  3299. (setq |#'shared-initialize| #'shared-initialize)
  3300. #|
  3301. (defmethod shared-initialize ((instance standard-object) slot-names &rest initargs &key &allow-other-keys)
  3302.   (dolist (slot (class-slots (class-of instance)))
  3303.     (let ((slotname (slotdef-name slot)))
  3304.       (multiple-value-bind (init-key init-value foundp)
  3305.           (get-properties initargs (slotdef-initargs slot))
  3306.         (declare (ignore init-key))
  3307.         (if foundp
  3308.           (setf (slot-value instance slotname) init-value)
  3309.           (unless (slot-boundp instance slotname)
  3310.             (let ((init (slotdef-initer slot)))
  3311.               (when init
  3312.                 (when (or (eq slot-names 'T) (member slotname slot-names :test #'eq))
  3313.                   (setf (slot-value instance slotname)
  3314.                         (if (car init) (funcall (car init)) (cdr init))
  3315.   ) ) ) ) ) ) ) ) )
  3316.   instance
  3317. )
  3318. |#
  3319. ; die Haupt-Arbeit erledigt ein SUBR:
  3320. (do-defmethod 'shared-initialize
  3321.   (make-standard-method
  3322.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3323.                       (cons #'clos::%shared-initialize '(T))
  3324.                     )
  3325.     :wants-next-method-p nil
  3326.     :parameter-specializers (list (find-class 'standard-object) (find-class 't))
  3327.     :qualifiers '()
  3328.     :signature '(2 0 t t () t)
  3329. ) )
  3330.  
  3331. ; 28.1.12.
  3332. (defgeneric reinitialize-instance (instance &rest initargs))
  3333. (setq |#'reinitialize-instance| #'reinitialize-instance)
  3334. #|
  3335. (defmethod reinitialize-instance ((instance standard-object) &rest initargs &key &allow-other-keys)
  3336.   (apply #'shared-initialize instance 'NIL initargs)
  3337. )
  3338. |#
  3339. #|
  3340. ; optimiert:
  3341. (defmethod reinitialize-instance ((instance standard-object) &rest initargs &key &allow-other-keys)
  3342.   (let ((h (gethash (class-of instance) *reinitialize-instance-table*)))
  3343.     (if h
  3344.       (progn
  3345.         ; 28.1.9.2. validity of initialization arguments
  3346.         (let ((valid-keywords (car h)))
  3347.           (sys::keyword-test initargs valid-keywords)
  3348.         )
  3349.         (if (not (eq (cdr h) #'clos::%shared-initialize))
  3350.           ; effektive Methode von shared-initialize anwenden:
  3351.           (apply (cdr h) instance 'NIL initargs)
  3352.           ; clos::%shared-initialize mit slot-names=NIL läßt sich vereinfachen:
  3353.           (progn
  3354.             (dolist (slot (class-slots (class-of instance)))
  3355.               (let ((slotname (slotdef-name slot)))
  3356.                 (multiple-value-bind (init-key init-value foundp)
  3357.                     (get-properties initargs (slotdef-initargs slot))
  3358.                   (declare (ignore init-key))
  3359.                   (if foundp
  3360.                     (setf (slot-value instance slotname) init-value)
  3361.             ) ) ) )
  3362.             instance
  3363.       ) ) )
  3364.       (apply #'initial-reinitialize-instance instance initargs)
  3365. ) ) )
  3366. |#
  3367. ; die Haupt-Arbeit erledigt ein SUBR:
  3368. (do-defmethod 'reinitialize-instance
  3369.   (make-standard-method
  3370.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3371.                       (cons #'clos::%reinitialize-instance '(T))
  3372.                     )
  3373.     :wants-next-method-p nil
  3374.     :parameter-specializers (list (find-class 'standard-object))
  3375.     :qualifiers '()
  3376.     :signature '(1 0 t t () t)
  3377. ) )
  3378. ; Beim ersten REINITIALIZE-INSTANCE-Aufruf einer jeden Klasse merkt man sich die
  3379. ; benötigte Information in *reinitialize-instance-table*.
  3380. (defun initial-reinitialize-instance (instance &rest initargs)
  3381.   (let* ((class (class-of instance))
  3382.          (valid-keywords
  3383.            (valid-initarg-keywords
  3384.              class
  3385.              ; Liste aller anwendbaren Methoden von SHARED-INITIALIZE
  3386.              (remove-if-not
  3387.                #'(lambda (method)
  3388.                    (let* ((specializers (std-method-parameter-specializers method))
  3389.                           (specializer1 (first specializers))
  3390.                           (specializer2 (second specializers)))
  3391.                      (and (atom specializer1) (subclassp class specializer1)
  3392.                           (typep 'NIL specializer2)
  3393.                  ) ) )
  3394.                (gf-methods |#'shared-initialize|)
  3395.         )) ) )
  3396.     ; 28.1.9.2. validity of initialization arguments
  3397.     (sys::keyword-test initargs valid-keywords)
  3398.     (let ((si-ef (compute-effective-method |#'shared-initialize| instance 'NIL)))
  3399.       (setf (gethash class *reinitialize-instance-table*) (cons valid-keywords si-ef))
  3400.       (apply si-ef instance 'NIL initargs)
  3401. ) ) )
  3402.  
  3403. ; 28.1.9.6.
  3404. (defgeneric initialize-instance (instance &rest initargs))
  3405. (setq |#'initialize-instance| #'initialize-instance)
  3406. #|
  3407. (defmethod initialize-instance ((instance standard-object) &rest initargs &key &allow-other-keys)
  3408.   (apply #'shared-initialize instance 'T initargs)
  3409. )
  3410. |#
  3411. #|
  3412. ; optimiert:
  3413. (defmethod initialize-instance ((instance standard-object) &rest initargs &key &allow-other-keys)
  3414.   (let ((h (gethash class *make-instance-table*)))
  3415.     (if h
  3416.       (if (not (eq (cddr h) #'clos::%shared-initialize))
  3417.         ; effektive Methode von shared-initialize anwenden:
  3418.         (apply (cddr h) instance 'T initargs)
  3419.         ; clos::%shared-initialize mit slot-names=T läßt sich vereinfachen:
  3420.         (progn
  3421.           (dolist (slot (class-slots (class-of instance)))
  3422.             (let ((slotname (slotdef-name slot)))
  3423.               (multiple-value-bind (init-key init-value foundp)
  3424.                   (get-properties initargs (slotdef-initargs slot))
  3425.                 (declare (ignore init-key))
  3426.                 (if foundp
  3427.                   (setf (slot-value instance slotname) init-value)
  3428.                   (unless (slot-boundp instance slotname)
  3429.                     (let ((init (slotdef-initer slot)))
  3430.                       (when init
  3431.                         (setf (slot-value instance slotname)
  3432.                               (if (car init) (funcall (car init)) (cdr init))
  3433.           ) ) ) ) ) ) ) )
  3434.           instance
  3435.       ) )
  3436.       (apply #'initial-initialize-instance instance initargs)
  3437. ) ) )
  3438. |#
  3439. ; die Haupt-Arbeit erledigt ein SUBR:
  3440. (do-defmethod 'initialize-instance
  3441.   (make-standard-method
  3442.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3443.                       (cons #'clos::%initialize-instance '(T))
  3444.                     )
  3445.     :wants-next-method-p nil
  3446.     :parameter-specializers (list (find-class 'standard-object))
  3447.     :qualifiers '()
  3448.     :signature '(1 0 t t () t)
  3449. ) )
  3450. (defun initial-initialize-instance (instance &rest initargs)
  3451.   (let* ((class (class-of instance))
  3452.          (valid-keywords (valid-make-instance-keywords class))
  3453.          (efs (make-instance-table-entry2 instance)))
  3454.     (setf (gethash class *make-instance-table*) (cons valid-keywords efs))
  3455.     ; effektive Methode von SHARED-INITIALIZE anwenden:
  3456.     (apply (cdr efs) instance 'T initargs)
  3457. ) )
  3458.  
  3459. ; 28.1.9.7.
  3460. (defgeneric make-instance (class &rest initargs)
  3461.   (:method ((class symbol) &rest initargs)
  3462.     (apply #'make-instance (find-class class) initargs)
  3463.   )
  3464. )
  3465. #|
  3466. (defmethod make-instance ((class standard-class) &rest initargs &key &allow-other-keys)
  3467.   ; 28.1.9.3., 28.1.9.4. default-initargs zur Kenntnis nehmen:
  3468.   (dolist (default-initarg (class-default-initargs class))
  3469.     (let ((nothing default-initarg))
  3470.       (when (eq (getf initargs (car default-initarg) nothing) nothing)
  3471.         (setq initargs
  3472.               (append initargs
  3473.                 (list (car default-initarg)
  3474.                       (let ((init (cdr default-initarg)))
  3475.                         (if (car init) (funcall (car init)) (cdr init))
  3476.   ) ) ) )     ) )     )
  3477.   #|
  3478.   ; 28.1.9.2. validity of initialization arguments
  3479.   (sys::keyword-test initargs
  3480.                      (union (class-valid-initargs class)
  3481.                             (applicable-keywords #'initialize-instance class) ; ??
  3482.   )                  )
  3483.   (let ((instance (std-allocate-instance class)))
  3484.     (apply #'initialize-instance instance initargs)
  3485.   )
  3486.   |#
  3487.   (let ((h (gethash class *make-instance-table*)))
  3488.     (if h
  3489.       (progn
  3490.         ; 28.1.9.2. validity of initialization arguments
  3491.         (let ((valid-keywords (car h)))
  3492.           (sys::keyword-test initargs valid-keywords)
  3493.         )
  3494.         (let ((instance (std-allocate-instance class)))
  3495.           (if (not (eq (cadr h) #'clos::%initialize-instance))
  3496.             ; effektive Methode von initialize-instance anwenden:
  3497.             (apply (cadr h) instance initargs)
  3498.             ; clos::%initialize-instance läßt sich vereinfachen (man braucht
  3499.             ; nicht nochmal in *make-instance-table* nachzusehen):
  3500.             (if (not (eq (cddr h) #'clos::%shared-initialize))
  3501.               ; effektive Methode von shared-initialize anwenden:
  3502.               (apply (cddr h) instance 'T initargs)
  3503.               ...
  3504.             )
  3505.       ) ) )
  3506.       (apply #'initial-make-instance class initargs)
  3507. ) ) )
  3508. |#
  3509. ; die Haupt-Arbeit erledigt ein SUBR:
  3510. (do-defmethod 'make-instance
  3511.   (make-standard-method
  3512.     :initfunction #'(lambda (gf) (declare (ignore gf))
  3513.                       (cons #'clos::%make-instance '(T))
  3514.                     )
  3515.     :wants-next-method-p nil
  3516.     :parameter-specializers (list (find-class 'standard-class))
  3517.     :qualifiers '()
  3518.     :signature '(1 0 t t () t)
  3519. ) )
  3520. (defun initial-make-instance (class &rest initargs)
  3521.   (let ((valid-keywords (valid-make-instance-keywords class)))
  3522.     ; 28.1.9.2. validity of initialization arguments
  3523.     (sys::keyword-test initargs valid-keywords)
  3524.     (let ((instance (std-allocate-instance class)))
  3525.       (let ((efs (make-instance-table-entry2 instance)))
  3526.         (setf (gethash class *make-instance-table*) (cons valid-keywords efs))
  3527.         ; effektive Methode von INITIALIZE-INSTANCE anwenden:
  3528.         (apply (car efs) instance initargs)
  3529. ) ) ) )
  3530.  
  3531.